aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-11-15 21:38:21 -0500
committerPaul Mackerras <paulus@samba.org>2005-11-15 21:52:21 -0500
commit94b212c29f685ca54b5689a8e89ac7671c43d651 (patch)
tree356266520a5ba530b2a5b77b68e90e87a2402ecb /arch/powerpc/boot
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/boot')
-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
17 files changed, 2213 insertions, 0 deletions
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
new file mode 100644
index 000000000000..9770f587af73
--- /dev/null
+++ b/arch/powerpc/boot/Makefile
@@ -0,0 +1,149 @@
1# Makefile for making ELF bootable images for booting on CHRP
2# using Open Firmware.
3#
4# Geert Uytterhoeven September 1997
5#
6# Based on coffboot by Paul Mackerras
7# Simplified for ppc64 by Todd Inglett
8#
9# NOTE: this code is built for 32 bit in ELF32 format even though
10# it packages a 64 bit kernel. We do this to simplify the
11# bootloader and increase compatibility with OpenFirmware.
12#
13# To this end we need to define BOOTCC, etc, as the tools
14# needed to build the 32 bit image. These are normally HOSTCC,
15# but may be a third compiler if, for example, you are cross
16# compiling from an intel box. Once the 64bit ppc gcc is
17# stable it will probably simply be a compiler switch to
18# compile for 32bit mode.
19# To make it easier to setup a cross compiler,
20# CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
21# in the toplevel makefile.
22
23
24HOSTCC := gcc
25BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
26 $(shell $(CROSS32CC) -print-file-name=include) -fPIC
27BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
28BOOTLFLAGS := -T $(srctree)/$(src)/zImage.lds
29OBJCOPYFLAGS := contents,alloc,load,readonly,data
30
31zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
32zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
33zliblinuxheader := zlib.h zconf.h zutil.h
34
35$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
36#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
37
38src-boot := string.S prom.c main.c div64.S crt0.S
39src-boot += $(zlib)
40src-boot := $(addprefix $(obj)/, $(src-boot))
41obj-boot := $(addsuffix .o, $(basename $(src-boot)))
42
43BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
44
45quiet_cmd_copy_zlib = COPY $@
46 cmd_copy_zlib = sed "s@__attribute_used__@@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
47
48quiet_cmd_copy_zlibheader = COPY $@
49 cmd_copy_zlibheader = sed "s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
50# stddef.h for NULL
51quiet_cmd_copy_zliblinuxheader = COPY $@
52 cmd_copy_zliblinuxheader = sed "s@<linux/string.h>@\"string.h\"@;s@<linux/kernel.h>@<stddef.h>@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
53
54$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
55 $(call cmd,copy_zlib)
56
57$(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
58 $(call cmd,copy_zlibheader)
59
60$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
61 $(call cmd,copy_zliblinuxheader)
62
63clean-files := $(zlib) $(zlibheader) $(zliblinuxheader)
64
65
66quiet_cmd_bootcc = BOOTCC $@
67 cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
68
69quiet_cmd_bootas = BOOTAS $@
70 cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
71
72quiet_cmd_bootld = BOOTLD $@
73 cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2)
74
75$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
76 $(call if_changed_dep,bootcc)
77$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
78 $(call if_changed_dep,bootas)
79
80#-----------------------------------------------------------
81# ELF sections within the zImage bootloader/wrapper
82#-----------------------------------------------------------
83required := vmlinux.strip
84initrd := initrd
85
86obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section)))
87src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
88gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
89
90hostprogs-y := addnote addRamDisk
91targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
92 $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
93 $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
94 $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
95 vmlinux.initrd
96extra-y := initrd.o
97
98quiet_cmd_ramdisk = RAMDISK $@
99 cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@
100
101quiet_cmd_stripvm = STRIP $@
102 cmd_stripvm = $(STRIP) -s -R .comment $< -o $@
103
104vmlinux.strip: vmlinux
105 $(call if_changed,stripvm)
106$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz
107 $(call if_changed,ramdisk)
108
109quiet_cmd_addsection = ADDSEC $@
110 cmd_addsection = $(CROSS32OBJCOPY) $@ \
111 --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \
112 --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS)
113
114quiet_cmd_addnote = ADDNOTE $@
115 cmd_addnote = $(obj)/addnote $@
116
117$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
118 $(call if_changed,gzip)
119
120$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz
121 cp -f $(obj)/ramdisk.image.gz $@
122
123$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz
124 @touch $@
125
126$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
127 $(call if_changed_dep,bootcc)
128 $(call cmd,addsection)
129
130$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required))
131$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
132 $(call cmd,bootld,$(obj-boot))
133
134$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd))
135$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
136 $(call cmd,bootld,$(obj-boot))
137
138$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote
139 @cp -f $< $@
140 $(call if_changed,addnote)
141
142$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
143 @cp -f $< $@
144 $(call if_changed,addnote)
145
146install: $(CONFIGURE) $(BOOTIMAGE)
147 sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
148
149clean-files := $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
diff --git a/arch/powerpc/boot/README b/arch/powerpc/boot/README
new file mode 100644
index 000000000000..3e11058760e4
--- /dev/null
+++ b/arch/powerpc/boot/README
@@ -0,0 +1,11 @@
1
2To extract the kernel vmlinux, System.map, .config or initrd from the zImage binary:
3
4objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz
5objcopy -j .kernel:System.map -O binary zImage System.map.gz
6objcopy -j .kernel:.config -O binary zImage config.gz
7objcopy -j .kernel:initrd -O binary zImage.initrd initrd.gz
8
9
10 Peter
11
diff --git a/arch/powerpc/boot/addRamDisk.c b/arch/powerpc/boot/addRamDisk.c
new file mode 100644
index 000000000000..c02a99952be7
--- /dev/null
+++ b/arch/powerpc/boot/addRamDisk.c
@@ -0,0 +1,311 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <netinet/in.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <string.h>
8#include <elf.h>
9
10#define ElfHeaderSize (64 * 1024)
11#define ElfPages (ElfHeaderSize / 4096)
12#define KERNELBASE (0xc000000000000000)
13#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
14
15struct addr_range {
16 unsigned long long addr;
17 unsigned long memsize;
18 unsigned long offset;
19};
20
21static int check_elf64(void *p, int size, struct addr_range *r)
22{
23 Elf64_Ehdr *elf64 = p;
24 Elf64_Phdr *elf64ph;
25
26 if (elf64->e_ident[EI_MAG0] != ELFMAG0 ||
27 elf64->e_ident[EI_MAG1] != ELFMAG1 ||
28 elf64->e_ident[EI_MAG2] != ELFMAG2 ||
29 elf64->e_ident[EI_MAG3] != ELFMAG3 ||
30 elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
31 elf64->e_ident[EI_DATA] != ELFDATA2MSB ||
32 elf64->e_type != ET_EXEC || elf64->e_machine != EM_PPC64)
33 return 0;
34
35 if ((elf64->e_phoff + sizeof(Elf64_Phdr)) > size)
36 return 0;
37
38 elf64ph = (Elf64_Phdr *) ((unsigned long)elf64 +
39 (unsigned long)elf64->e_phoff);
40
41 r->memsize = (unsigned long)elf64ph->p_memsz;
42 r->offset = (unsigned long)elf64ph->p_offset;
43 r->addr = (unsigned long long)elf64ph->p_vaddr;
44
45#ifdef DEBUG
46 printf("PPC64 ELF file, ph:\n");
47 printf("p_type 0x%08x\n", elf64ph->p_type);
48 printf("p_flags 0x%08x\n", elf64ph->p_flags);
49 printf("p_offset 0x%016llx\n", elf64ph->p_offset);
50 printf("p_vaddr 0x%016llx\n", elf64ph->p_vaddr);
51 printf("p_paddr 0x%016llx\n", elf64ph->p_paddr);
52 printf("p_filesz 0x%016llx\n", elf64ph->p_filesz);
53 printf("p_memsz 0x%016llx\n", elf64ph->p_memsz);
54 printf("p_align 0x%016llx\n", elf64ph->p_align);
55 printf("... skipping 0x%08lx bytes of ELF header\n",
56 (unsigned long)elf64ph->p_offset);
57#endif
58
59 return 64;
60}
61void get4k(FILE *file, char *buf )
62{
63 unsigned j;
64 unsigned num = fread(buf, 1, 4096, file);
65 for ( j=num; j<4096; ++j )
66 buf[j] = 0;
67}
68
69void put4k(FILE *file, char *buf )
70{
71 fwrite(buf, 1, 4096, file);
72}
73
74void death(const char *msg, FILE *fdesc, const char *fname)
75{
76 fprintf(stderr, msg);
77 fclose(fdesc);
78 unlink(fname);
79 exit(1);
80}
81
82int main(int argc, char **argv)
83{
84 char inbuf[4096];
85 struct addr_range vmlinux;
86 FILE *ramDisk;
87 FILE *inputVmlinux;
88 FILE *outputVmlinux;
89
90 char *rd_name, *lx_name, *out_name;
91
92 size_t i;
93 unsigned long ramFileLen;
94 unsigned long ramLen;
95 unsigned long roundR;
96 unsigned long offset_end;
97
98 unsigned long kernelLen;
99 unsigned long actualKernelLen;
100 unsigned long round;
101 unsigned long roundedKernelLen;
102 unsigned long ramStartOffs;
103 unsigned long ramPages;
104 unsigned long roundedKernelPages;
105 unsigned long hvReleaseData;
106 u_int32_t eyeCatcher = 0xc8a5d9c4;
107 unsigned long naca;
108 unsigned long xRamDisk;
109 unsigned long xRamDiskSize;
110 long padPages;
111
112
113 if (argc < 2) {
114 fprintf(stderr, "Name of RAM disk file missing.\n");
115 exit(1);
116 }
117 rd_name = argv[1];
118
119 if (argc < 3) {
120 fprintf(stderr, "Name of vmlinux file missing.\n");
121 exit(1);
122 }
123 lx_name = argv[2];
124
125 if (argc < 4) {
126 fprintf(stderr, "Name of vmlinux output file missing.\n");
127 exit(1);
128 }
129 out_name = argv[3];
130
131
132 ramDisk = fopen(rd_name, "r");
133 if ( ! ramDisk ) {
134 fprintf(stderr, "RAM disk file \"%s\" failed to open.\n", rd_name);
135 exit(1);
136 }
137
138 inputVmlinux = fopen(lx_name, "r");
139 if ( ! inputVmlinux ) {
140 fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", lx_name);
141 exit(1);
142 }
143
144 outputVmlinux = fopen(out_name, "w+");
145 if ( ! outputVmlinux ) {
146 fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", out_name);
147 exit(1);
148 }
149
150 i = fread(inbuf, 1, sizeof(inbuf), inputVmlinux);
151 if (i != sizeof(inbuf)) {
152 fprintf(stderr, "can not read vmlinux file %s: %u\n", lx_name, i);
153 exit(1);
154 }
155
156 i = check_elf64(inbuf, sizeof(inbuf), &vmlinux);
157 if (i == 0) {
158 fprintf(stderr, "You must have a linux kernel specified as argv[2]\n");
159 exit(1);
160 }
161
162 /* Input Vmlinux file */
163 fseek(inputVmlinux, 0, SEEK_END);
164 kernelLen = ftell(inputVmlinux);
165 fseek(inputVmlinux, 0, SEEK_SET);
166 printf("kernel file size = %lu\n", kernelLen);
167
168 actualKernelLen = kernelLen - ElfHeaderSize;
169
170 printf("actual kernel length (minus ELF header) = %lu\n", actualKernelLen);
171
172 round = actualKernelLen % 4096;
173 roundedKernelLen = actualKernelLen;
174 if ( round )
175 roundedKernelLen += (4096 - round);
176 printf("Vmlinux length rounded up to a 4k multiple = %ld/0x%lx \n", roundedKernelLen, roundedKernelLen);
177 roundedKernelPages = roundedKernelLen / 4096;
178 printf("Vmlinux pages to copy = %ld/0x%lx \n", roundedKernelPages, roundedKernelPages);
179
180 offset_end = _ALIGN_UP(vmlinux.memsize, 4096);
181 /* calc how many pages we need to insert between the vmlinux and the start of the ram disk */
182 padPages = offset_end/4096 - roundedKernelPages;
183
184 /* Check and see if the vmlinux is already larger than _end in System.map */
185 if (padPages < 0) {
186 /* vmlinux is larger than _end - adjust the offset to the start of the embedded ram disk */
187 offset_end = roundedKernelLen;
188 printf("vmlinux is larger than _end indicates it needs to be - offset_end = %lx \n", offset_end);
189 padPages = 0;
190 printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
191 }
192 else {
193 /* _end is larger than vmlinux - use the offset to _end that we calculated from the system map */
194 printf("vmlinux is smaller than _end indicates is needed - offset_end = %lx \n", offset_end);
195 printf("will insert %lx pages between the vmlinux and the start of the ram disk \n", padPages);
196 }
197
198
199
200 /* Input Ram Disk file */
201 // Set the offset that the ram disk will be started at.
202 ramStartOffs = offset_end; /* determined from the input vmlinux file and the system map */
203 printf("Ram Disk will start at offset = 0x%lx \n", ramStartOffs);
204
205 fseek(ramDisk, 0, SEEK_END);
206 ramFileLen = ftell(ramDisk);
207 fseek(ramDisk, 0, SEEK_SET);
208 printf("%s file size = %ld/0x%lx \n", rd_name, ramFileLen, ramFileLen);
209
210 ramLen = ramFileLen;
211
212 roundR = 4096 - (ramLen % 4096);
213 if ( roundR ) {
214 printf("Rounding RAM disk file up to a multiple of 4096, adding %ld/0x%lx \n", roundR, roundR);
215 ramLen += roundR;
216 }
217
218 printf("Rounded RAM disk size is %ld/0x%lx \n", ramLen, ramLen);
219 ramPages = ramLen / 4096;
220 printf("RAM disk pages to copy = %ld/0x%lx\n", ramPages, ramPages);
221
222
223
224 // Copy 64K ELF header
225 for (i=0; i<(ElfPages); ++i) {
226 get4k( inputVmlinux, inbuf );
227 put4k( outputVmlinux, inbuf );
228 }
229
230 /* Copy the vmlinux (as full pages). */
231 fseek(inputVmlinux, ElfHeaderSize, SEEK_SET);
232 for ( i=0; i<roundedKernelPages; ++i ) {
233 get4k( inputVmlinux, inbuf );
234 put4k( outputVmlinux, inbuf );
235 }
236
237 /* Insert pad pages (if appropriate) that are needed between */
238 /* | the end of the vmlinux and the ram disk. */
239 for (i=0; i<padPages; ++i) {
240 memset(inbuf, 0, 4096);
241 put4k(outputVmlinux, inbuf);
242 }
243
244 /* Copy the ram disk (as full pages). */
245 for ( i=0; i<ramPages; ++i ) {
246 get4k( ramDisk, inbuf );
247 put4k( outputVmlinux, inbuf );
248 }
249
250 /* Close the input files */
251 fclose(ramDisk);
252 fclose(inputVmlinux);
253 /* And flush the written output file */
254 fflush(outputVmlinux);
255
256
257
258 /* Fixup the new vmlinux to contain the ram disk starting offset (xRamDisk) and the ram disk size (xRamDiskSize) */
259 /* fseek to the hvReleaseData pointer */
260 fseek(outputVmlinux, ElfHeaderSize + 0x24, SEEK_SET);
261 if (fread(&hvReleaseData, 4, 1, outputVmlinux) != 1) {
262 death("Could not read hvReleaseData pointer\n", outputVmlinux, out_name);
263 }
264 hvReleaseData = ntohl(hvReleaseData); /* Convert to native int */
265 printf("hvReleaseData is at %08lx\n", hvReleaseData);
266
267 /* fseek to the hvReleaseData */
268 fseek(outputVmlinux, ElfHeaderSize + hvReleaseData, SEEK_SET);
269 if (fread(inbuf, 0x40, 1, outputVmlinux) != 1) {
270 death("Could not read hvReleaseData\n", outputVmlinux, out_name);
271 }
272 /* Check hvReleaseData sanity */
273 if (memcmp(inbuf, &eyeCatcher, 4) != 0) {
274 death("hvReleaseData is invalid\n", outputVmlinux, out_name);
275 }
276 /* Get the naca pointer */
277 naca = ntohl(*((u_int32_t*) &inbuf[0x0C])) - KERNELBASE;
278 printf("Naca is at offset 0x%lx \n", naca);
279
280 /* fseek to the naca */
281 fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
282 if (fread(inbuf, 0x18, 1, outputVmlinux) != 1) {
283 death("Could not read naca\n", outputVmlinux, out_name);
284 }
285 xRamDisk = ntohl(*((u_int32_t *) &inbuf[0x0c]));
286 xRamDiskSize = ntohl(*((u_int32_t *) &inbuf[0x14]));
287 /* Make sure a RAM disk isn't already present */
288 if ((xRamDisk != 0) || (xRamDiskSize != 0)) {
289 death("RAM disk is already attached to this kernel\n", outputVmlinux, out_name);
290 }
291 /* Fill in the values */
292 *((u_int32_t *) &inbuf[0x0c]) = htonl(ramStartOffs);
293 *((u_int32_t *) &inbuf[0x14]) = htonl(ramPages);
294
295 /* Write out the new naca */
296 fflush(outputVmlinux);
297 fseek(outputVmlinux, ElfHeaderSize + naca, SEEK_SET);
298 if (fwrite(inbuf, 0x18, 1, outputVmlinux) != 1) {
299 death("Could not write naca\n", outputVmlinux, out_name);
300 }
301 printf("Ram Disk of 0x%lx pages is attached to the kernel at offset 0x%08lx\n",
302 ramPages, ramStartOffs);
303
304 /* Done */
305 fclose(outputVmlinux);
306 /* Set permission to executable */
307 chmod(out_name, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
308
309 return 0;
310}
311
diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c
new file mode 100644
index 000000000000..8041a9845ab7
--- /dev/null
+++ b/arch/powerpc/boot/addnote.c
@@ -0,0 +1,205 @@
1/*
2 * Program to hack in a PT_NOTE program header entry in an ELF file.
3 * This is needed for OF on RS/6000s to load an image correctly.
4 * Note that OF needs a program header entry for the note, not an
5 * ELF section.
6 *
7 * Copyright 2000 Paul Mackerras.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Usage: addnote zImage
15 */
16#include <stdio.h>
17#include <stdlib.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <string.h>
21
22/* CHRP note section */
23char arch[] = "PowerPC";
24
25#define N_DESCR 6
26unsigned int descr[N_DESCR] = {
27 0xffffffff, /* real-mode = true */
28 0x00c00000, /* real-base, i.e. where we expect OF to be */
29 0xffffffff, /* real-size */
30 0xffffffff, /* virt-base */
31 0xffffffff, /* virt-size */
32 0x4000, /* load-base */
33};
34
35/* RPA note section */
36char rpaname[] = "IBM,RPA-Client-Config";
37
38/*
39 * Note: setting ignore_my_client_config *should* mean that OF ignores
40 * all the other fields, but there is a firmware bug which means that
41 * it looks at the splpar field at least. So these values need to be
42 * reasonable.
43 */
44#define N_RPA_DESCR 8
45unsigned int rpanote[N_RPA_DESCR] = {
46 0, /* lparaffinity */
47 64, /* min_rmo_size */
48 0, /* min_rmo_percent */
49 40, /* max_pft_size */
50 1, /* splpar */
51 -1, /* min_load */
52 0, /* new_mem_def */
53 1, /* ignore_my_client_config */
54};
55
56#define ROUNDUP(len) (((len) + 3) & ~3)
57
58unsigned char buf[512];
59
60#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
61#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2))
62
63#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \
64 buf[(off) + 1] = (v) & 0xff)
65#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \
66 PUT_16BE((off) + 2, (v)))
67
68/* Structure of an ELF file */
69#define E_IDENT 0 /* ELF header */
70#define E_PHOFF 28
71#define E_PHENTSIZE 42
72#define E_PHNUM 44
73#define E_HSIZE 52 /* size of ELF header */
74
75#define EI_MAGIC 0 /* offsets in E_IDENT area */
76#define EI_CLASS 4
77#define EI_DATA 5
78
79#define PH_TYPE 0 /* ELF program header */
80#define PH_OFFSET 4
81#define PH_FILESZ 16
82#define PH_HSIZE 32 /* size of program header */
83
84#define PT_NOTE 4 /* Program header type = note */
85
86#define ELFCLASS32 1
87#define ELFDATA2MSB 2
88
89unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
90
91int
92main(int ac, char **av)
93{
94 int fd, n, i;
95 int ph, ps, np;
96 int nnote, nnote2, ns;
97
98 if (ac != 2) {
99 fprintf(stderr, "Usage: %s elf-file\n", av[0]);
100 exit(1);
101 }
102 fd = open(av[1], O_RDWR);
103 if (fd < 0) {
104 perror(av[1]);
105 exit(1);
106 }
107
108 nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
109 nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
110
111 n = read(fd, buf, sizeof(buf));
112 if (n < 0) {
113 perror("read");
114 exit(1);
115 }
116
117 if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0)
118 goto notelf;
119
120 if (buf[E_IDENT+EI_CLASS] != ELFCLASS32
121 || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) {
122 fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n",
123 av[1]);
124 exit(1);
125 }
126
127 ph = GET_32BE(E_PHOFF);
128 ps = GET_16BE(E_PHENTSIZE);
129 np = GET_16BE(E_PHNUM);
130 if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
131 goto notelf;
132 if (ph + (np + 2) * ps + nnote + nnote2 > n)
133 goto nospace;
134
135 for (i = 0; i < np; ++i) {
136 if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
137 fprintf(stderr, "%s already has a note entry\n",
138 av[1]);
139 exit(0);
140 }
141 ph += ps;
142 }
143
144 /* XXX check that the area we want to use is all zeroes */
145 for (i = 0; i < 2 * ps + nnote + nnote2; ++i)
146 if (buf[ph + i] != 0)
147 goto nospace;
148
149 /* fill in the program header entry */
150 ns = ph + 2 * ps;
151 PUT_32BE(ph + PH_TYPE, PT_NOTE);
152 PUT_32BE(ph + PH_OFFSET, ns);
153 PUT_32BE(ph + PH_FILESZ, nnote);
154
155 /* fill in the note area we point to */
156 /* XXX we should probably make this a proper section */
157 PUT_32BE(ns, strlen(arch) + 1);
158 PUT_32BE(ns + 4, N_DESCR * 4);
159 PUT_32BE(ns + 8, 0x1275);
160 strcpy((char *) &buf[ns + 12], arch);
161 ns += 12 + strlen(arch) + 1;
162 for (i = 0; i < N_DESCR; ++i, ns += 4)
163 PUT_32BE(ns, descr[i]);
164
165 /* fill in the second program header entry and the RPA note area */
166 ph += ps;
167 PUT_32BE(ph + PH_TYPE, PT_NOTE);
168 PUT_32BE(ph + PH_OFFSET, ns);
169 PUT_32BE(ph + PH_FILESZ, nnote2);
170
171 /* fill in the note area we point to */
172 PUT_32BE(ns, strlen(rpaname) + 1);
173 PUT_32BE(ns + 4, sizeof(rpanote));
174 PUT_32BE(ns + 8, 0x12759999);
175 strcpy((char *) &buf[ns + 12], rpaname);
176 ns += 12 + ROUNDUP(strlen(rpaname) + 1);
177 for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
178 PUT_32BE(ns, rpanote[i]);
179
180 /* Update the number of program headers */
181 PUT_16BE(E_PHNUM, np + 2);
182
183 /* write back */
184 lseek(fd, (long) 0, SEEK_SET);
185 i = write(fd, buf, n);
186 if (i < 0) {
187 perror("write");
188 exit(1);
189 }
190 if (i < n) {
191 fprintf(stderr, "%s: write truncated\n", av[1]);
192 exit(1);
193 }
194
195 exit(0);
196
197 notelf:
198 fprintf(stderr, "%s does not appear to be an ELF file\n", av[1]);
199 exit(1);
200
201 nospace:
202 fprintf(stderr, "sorry, I can't find space in %s to put the note\n",
203 av[1]);
204 exit(1);
205}
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
new file mode 100644
index 000000000000..9cc442263939
--- /dev/null
+++ b/arch/powerpc/boot/crt0.S
@@ -0,0 +1,59 @@
1/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * NOTE: this code runs in 32 bit mode and is packaged as ELF32.
10 */
11
12#include "ppc_asm.h"
13
14 .text
15 .globl _zimage_start
16_zimage_start:
17 bl reloc_offset
18
19reloc_offset:
20 mflr r0
21 lis r9,reloc_offset@ha
22 addi r9,r9,reloc_offset@l
23 subf. r0,r9,r0
24 beq clear_caches
25
26reloc_got2:
27 lis r9,__got2_start@ha
28 addi r9,r9,__got2_start@l
29 lis r8,__got2_end@ha
30 addi r8,r8,__got2_end@l
31 subf. r8,r9,r8
32 beq clear_caches
33 srwi. r8,r8,2
34 mtctr r8
35 add r9,r0,r9
36reloc_got2_loop:
37 lwz r8,0(r9)
38 add r8,r8,r0
39 stw r8,0(r9)
40 addi r9,r9,4
41 bdnz reloc_got2_loop
42
43clear_caches:
44 lis r9,_start@h
45 add r9,r0,r9
46 lis r8,_etext@ha
47 addi r8,r8,_etext@l
48 add r8,r0,r8
491: dcbf r0,r9
50 icbi r0,r9
51 addi r9,r9,0x20
52 cmplwi 0,r9,8
53 blt 1b
54 sync
55 isync
56
57 mr r6,r1
58 b start
59
diff --git a/arch/powerpc/boot/div64.S b/arch/powerpc/boot/div64.S
new file mode 100644
index 000000000000..722f360a32a9
--- /dev/null
+++ b/arch/powerpc/boot/div64.S
@@ -0,0 +1,58 @@
1/*
2 * Divide a 64-bit unsigned number by a 32-bit unsigned number.
3 * This routine assumes that the top 32 bits of the dividend are
4 * non-zero to start with.
5 * On entry, r3 points to the dividend, which get overwritten with
6 * the 64-bit quotient, and r4 contains the divisor.
7 * On exit, r3 contains the remainder.
8 *
9 * Copyright (C) 2002 Paul Mackerras, IBM Corp.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 */
16#include "ppc_asm.h"
17
18 .globl __div64_32
19__div64_32:
20 lwz r5,0(r3) # get the dividend into r5/r6
21 lwz r6,4(r3)
22 cmplw r5,r4
23 li r7,0
24 li r8,0
25 blt 1f
26 divwu r7,r5,r4 # if dividend.hi >= divisor,
27 mullw r0,r7,r4 # quotient.hi = dividend.hi / divisor
28 subf. r5,r0,r5 # dividend.hi %= divisor
29 beq 3f
301: mr r11,r5 # here dividend.hi != 0
31 andis. r0,r5,0xc000
32 bne 2f
33 cntlzw r0,r5 # we are shifting the dividend right
34 li r10,-1 # to make it < 2^32, and shifting
35 srw r10,r10,r0 # the divisor right the same amount,
36 add r9,r4,r10 # rounding up (so the estimate cannot
37 andc r11,r6,r10 # ever be too large, only too small)
38 andc r9,r9,r10
39 or r11,r5,r11
40 rotlw r9,r9,r0
41 rotlw r11,r11,r0
42 divwu r11,r11,r9 # then we divide the shifted quantities
432: mullw r10,r11,r4 # to get an estimate of the quotient,
44 mulhwu r9,r11,r4 # multiply the estimate by the divisor,
45 subfc r6,r10,r6 # take the product from the divisor,
46 add r8,r8,r11 # and add the estimate to the accumulated
47 subfe. r5,r9,r5 # quotient
48 bne 1b
493: cmplw r6,r4
50 blt 4f
51 divwu r0,r6,r4 # perform the remaining 32-bit division
52 mullw r10,r0,r4 # and get the remainder
53 add r8,r8,r0
54 subf r6,r10,r6
554: stw r7,0(r3) # return the quotient in *r3
56 stw r8,4(r3)
57 mr r3,r6 # return the remainder in r3
58 blr
diff --git a/arch/powerpc/boot/elf.h b/arch/powerpc/boot/elf.h
new file mode 100644
index 000000000000..d4828fcf1cb9
--- /dev/null
+++ b/arch/powerpc/boot/elf.h
@@ -0,0 +1,149 @@
1#ifndef _PPC_BOOT_ELF_H_
2#define _PPC_BOOT_ELF_H_
3
4/* 32-bit ELF base types. */
5typedef unsigned int Elf32_Addr;
6typedef unsigned short Elf32_Half;
7typedef unsigned int Elf32_Off;
8typedef signed int Elf32_Sword;
9typedef unsigned int Elf32_Word;
10
11/* 64-bit ELF base types. */
12typedef unsigned long long Elf64_Addr;
13typedef unsigned short Elf64_Half;
14typedef signed short Elf64_SHalf;
15typedef unsigned long long Elf64_Off;
16typedef signed int Elf64_Sword;
17typedef unsigned int Elf64_Word;
18typedef unsigned long long Elf64_Xword;
19typedef signed long long Elf64_Sxword;
20
21/* These constants are for the segment types stored in the image headers */
22#define PT_NULL 0
23#define PT_LOAD 1
24#define PT_DYNAMIC 2
25#define PT_INTERP 3
26#define PT_NOTE 4
27#define PT_SHLIB 5
28#define PT_PHDR 6
29#define PT_TLS 7 /* Thread local storage segment */
30#define PT_LOOS 0x60000000 /* OS-specific */
31#define PT_HIOS 0x6fffffff /* OS-specific */
32#define PT_LOPROC 0x70000000
33#define PT_HIPROC 0x7fffffff
34#define PT_GNU_EH_FRAME 0x6474e550
35
36#define PT_GNU_STACK (PT_LOOS + 0x474e551)
37
38/* These constants define the different elf file types */
39#define ET_NONE 0
40#define ET_REL 1
41#define ET_EXEC 2
42#define ET_DYN 3
43#define ET_CORE 4
44#define ET_LOPROC 0xff00
45#define ET_HIPROC 0xffff
46
47/* These constants define the various ELF target machines */
48#define EM_NONE 0
49#define EM_PPC 20 /* PowerPC */
50#define EM_PPC64 21 /* PowerPC64 */
51
52#define EI_NIDENT 16
53
54typedef struct elf32_hdr {
55 unsigned char e_ident[EI_NIDENT];
56 Elf32_Half e_type;
57 Elf32_Half e_machine;
58 Elf32_Word e_version;
59 Elf32_Addr e_entry; /* Entry point */
60 Elf32_Off e_phoff;
61 Elf32_Off e_shoff;
62 Elf32_Word e_flags;
63 Elf32_Half e_ehsize;
64 Elf32_Half e_phentsize;
65 Elf32_Half e_phnum;
66 Elf32_Half e_shentsize;
67 Elf32_Half e_shnum;
68 Elf32_Half e_shstrndx;
69} Elf32_Ehdr;
70
71typedef struct elf64_hdr {
72 unsigned char e_ident[16]; /* ELF "magic number" */
73 Elf64_Half e_type;
74 Elf64_Half e_machine;
75 Elf64_Word e_version;
76 Elf64_Addr e_entry; /* Entry point virtual address */
77 Elf64_Off e_phoff; /* Program header table file offset */
78 Elf64_Off e_shoff; /* Section header table file offset */
79 Elf64_Word e_flags;
80 Elf64_Half e_ehsize;
81 Elf64_Half e_phentsize;
82 Elf64_Half e_phnum;
83 Elf64_Half e_shentsize;
84 Elf64_Half e_shnum;
85 Elf64_Half e_shstrndx;
86} Elf64_Ehdr;
87
88/* These constants define the permissions on sections in the program
89 header, p_flags. */
90#define PF_R 0x4
91#define PF_W 0x2
92#define PF_X 0x1
93
94typedef struct elf32_phdr {
95 Elf32_Word p_type;
96 Elf32_Off p_offset;
97 Elf32_Addr p_vaddr;
98 Elf32_Addr p_paddr;
99 Elf32_Word p_filesz;
100 Elf32_Word p_memsz;
101 Elf32_Word p_flags;
102 Elf32_Word p_align;
103} Elf32_Phdr;
104
105typedef struct elf64_phdr {
106 Elf64_Word p_type;
107 Elf64_Word p_flags;
108 Elf64_Off p_offset; /* Segment file offset */
109 Elf64_Addr p_vaddr; /* Segment virtual address */
110 Elf64_Addr p_paddr; /* Segment physical address */
111 Elf64_Xword p_filesz; /* Segment size in file */
112 Elf64_Xword p_memsz; /* Segment size in memory */
113 Elf64_Xword p_align; /* Segment alignment, file & memory */
114} Elf64_Phdr;
115
116#define EI_MAG0 0 /* e_ident[] indexes */
117#define EI_MAG1 1
118#define EI_MAG2 2
119#define EI_MAG3 3
120#define EI_CLASS 4
121#define EI_DATA 5
122#define EI_VERSION 6
123#define EI_OSABI 7
124#define EI_PAD 8
125
126#define ELFMAG0 0x7f /* EI_MAG */
127#define ELFMAG1 'E'
128#define ELFMAG2 'L'
129#define ELFMAG3 'F'
130#define ELFMAG "\177ELF"
131#define SELFMAG 4
132
133#define ELFCLASSNONE 0 /* EI_CLASS */
134#define ELFCLASS32 1
135#define ELFCLASS64 2
136#define ELFCLASSNUM 3
137
138#define ELFDATANONE 0 /* e_ident[EI_DATA] */
139#define ELFDATA2LSB 1
140#define ELFDATA2MSB 2
141
142#define EV_NONE 0 /* e_version, EI_VERSION */
143#define EV_CURRENT 1
144#define EV_NUM 2
145
146#define ELFOSABI_NONE 0
147#define ELFOSABI_LINUX 3
148
149#endif /* _PPC_BOOT_ELF_H_ */
diff --git a/arch/powerpc/boot/install.sh b/arch/powerpc/boot/install.sh
new file mode 100644
index 000000000000..eacce9590816
--- /dev/null
+++ b/arch/powerpc/boot/install.sh
@@ -0,0 +1,42 @@
1#!/bin/sh
2#
3# arch/ppc64/boot/install.sh
4#
5# This file is subject to the terms and conditions of the GNU General Public
6# License. See the file "COPYING" in the main directory of this archive
7# for more details.
8#
9# Copyright (C) 1995 by Linus Torvalds
10#
11# Blatantly stolen from in arch/i386/boot/install.sh by Dave Hansen
12#
13# "make install" script for ppc64 architecture
14#
15# Arguments:
16# $1 - kernel version
17# $2 - kernel image file
18# $3 - kernel map file
19# $4 - default install path (blank if root directory)
20# $5 - kernel boot file, the zImage
21#
22
23# User may have a custom install script
24
25if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
26if [ -x /sbin/${CROSS_COMPILE}installkernel ]; then exec /sbin/${CROSS_COMPILE}installkernel "$@"; fi
27
28# Default install
29
30# this should work for both the pSeries zImage and the iSeries vmlinux.sm
31image_name=`basename $2`
32
33if [ -f $4/$image_name ]; then
34 mv $4/$image_name $4/$image_name.old
35fi
36
37if [ -f $4/System.map ]; then
38 mv $4/System.map $4/System.old
39fi
40
41cat $2 > $4/$image_name
42cp $3 $4/System.map
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
new file mode 100644
index 000000000000..64ec93116fa6
--- /dev/null
+++ b/arch/powerpc/boot/main.c
@@ -0,0 +1,321 @@
1/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <stdarg.h>
12#include <stddef.h>
13#include "elf.h"
14#include "page.h"
15#include "string.h"
16#include "stdio.h"
17#include "prom.h"
18#include "zlib.h"
19
20extern void flush_cache(void *, unsigned long);
21
22
23/* Value picked to match that used by yaboot */
24#define PROG_START 0x01400000
25#define RAM_END (512<<20) // Fixme: use OF */
26#define ONE_MB 0x100000
27
28extern char _start[];
29extern char __bss_start[];
30extern char _end[];
31extern char _vmlinux_start[];
32extern char _vmlinux_end[];
33extern char _initrd_start[];
34extern char _initrd_end[];
35
36struct addr_range {
37 unsigned long addr;
38 unsigned long size;
39 unsigned long memsize;
40};
41static struct addr_range vmlinux;
42static struct addr_range vmlinuz;
43static struct addr_range initrd;
44
45static unsigned long elfoffset;
46
47static char scratch[46912]; /* scratch space for gunzip, from zlib_inflate_workspacesize() */
48static char elfheader[256];
49
50
51typedef void (*kernel_entry_t)( unsigned long,
52 unsigned long,
53 void *,
54 void *);
55
56
57#undef DEBUG
58
59static unsigned long claim_base;
60
61#define HEAD_CRC 2
62#define EXTRA_FIELD 4
63#define ORIG_NAME 8
64#define COMMENT 0x10
65#define RESERVED 0xe0
66
67static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
68{
69 z_stream s;
70 int r, i, flags;
71
72 /* skip header */
73 i = 10;
74 flags = src[3];
75 if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
76 printf("bad gzipped data\n\r");
77 exit();
78 }
79 if ((flags & EXTRA_FIELD) != 0)
80 i = 12 + src[10] + (src[11] << 8);
81 if ((flags & ORIG_NAME) != 0)
82 while (src[i++] != 0)
83 ;
84 if ((flags & COMMENT) != 0)
85 while (src[i++] != 0)
86 ;
87 if ((flags & HEAD_CRC) != 0)
88 i += 2;
89 if (i >= *lenp) {
90 printf("gunzip: ran out of data in header\n\r");
91 exit();
92 }
93
94 if (zlib_inflate_workspacesize() > sizeof(scratch)) {
95 printf("gunzip needs more mem\n");
96 exit();
97 }
98 memset(&s, 0, sizeof(s));
99 s.workspace = scratch;
100 r = zlib_inflateInit2(&s, -MAX_WBITS);
101 if (r != Z_OK) {
102 printf("inflateInit2 returned %d\n\r", r);
103 exit();
104 }
105 s.next_in = src + i;
106 s.avail_in = *lenp - i;
107 s.next_out = dst;
108 s.avail_out = dstlen;
109 r = zlib_inflate(&s, Z_FULL_FLUSH);
110 if (r != Z_OK && r != Z_STREAM_END) {
111 printf("inflate returned %d msg: %s\n\r", r, s.msg);
112 exit();
113 }
114 *lenp = s.next_out - (unsigned char *) dst;
115 zlib_inflateEnd(&s);
116}
117
118static unsigned long try_claim(unsigned long size)
119{
120 unsigned long addr = 0;
121
122 for(; claim_base < RAM_END; claim_base += ONE_MB) {
123#ifdef DEBUG
124 printf(" trying: 0x%08lx\n\r", claim_base);
125#endif
126 addr = (unsigned long)claim(claim_base, size, 0);
127 if ((void *)addr != (void *)-1)
128 break;
129 }
130 if (addr == 0)
131 return 0;
132 claim_base = PAGE_ALIGN(claim_base + size);
133 return addr;
134}
135
136static int is_elf64(void *hdr)
137{
138 Elf64_Ehdr *elf64 = hdr;
139 Elf64_Phdr *elf64ph;
140 unsigned int i;
141
142 if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 &&
143 elf64->e_ident[EI_MAG1] == ELFMAG1 &&
144 elf64->e_ident[EI_MAG2] == ELFMAG2 &&
145 elf64->e_ident[EI_MAG3] == ELFMAG3 &&
146 elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
147 elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
148 elf64->e_type == ET_EXEC &&
149 elf64->e_machine == EM_PPC64))
150 return 0;
151
152 elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
153 (unsigned long)elf64->e_phoff);
154 for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
155 if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0)
156 break;
157 if (i >= (unsigned int)elf64->e_phnum)
158 return 0;
159
160 elfoffset = (unsigned long)elf64ph->p_offset;
161 vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
162 vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
163 return 1;
164}
165
166static int is_elf32(void *hdr)
167{
168 Elf32_Ehdr *elf32 = hdr;
169 Elf32_Phdr *elf32ph;
170 unsigned int i;
171
172 if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 &&
173 elf32->e_ident[EI_MAG1] == ELFMAG1 &&
174 elf32->e_ident[EI_MAG2] == ELFMAG2 &&
175 elf32->e_ident[EI_MAG3] == ELFMAG3 &&
176 elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
177 elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
178 elf32->e_type == ET_EXEC &&
179 elf32->e_machine == EM_PPC))
180 return 0;
181
182 elf32 = (Elf32_Ehdr *)elfheader;
183 elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
184 for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
185 if (elf32ph->p_type == PT_LOAD && elf32ph->p_offset != 0)
186 break;
187 if (i >= elf32->e_phnum)
188 return 0;
189
190 elfoffset = elf32ph->p_offset;
191 vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
192 vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
193 return 1;
194}
195
196void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
197{
198 int len;
199 kernel_entry_t kernel_entry;
200
201 memset(__bss_start, 0, _end - __bss_start);
202
203 prom = (int (*)(void *)) promptr;
204 chosen_handle = finddevice("/chosen");
205 if (chosen_handle == (void *) -1)
206 exit();
207 if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
208 exit();
209 stderr = stdout;
210 if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
211 exit();
212
213 printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
214
215 vmlinuz.addr = (unsigned long)_vmlinux_start;
216 vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
217
218 /* gunzip the ELF header of the kernel */
219 if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
220 len = vmlinuz.size;
221 gunzip(elfheader, sizeof(elfheader),
222 (unsigned char *)vmlinuz.addr, &len);
223 } else
224 memcpy(elfheader, (const void *)vmlinuz.addr, sizeof(elfheader));
225
226 if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
227 printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
228 exit();
229 }
230
231 /*
232 * The first available claim_base must be above the end of the
233 * the loaded kernel wrapper file (_start to _end includes the
234 * initrd image if it is present) and rounded up to a nice
235 * 1 MB boundary for good measure.
236 */
237
238 claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
239
240#if defined(PROG_START)
241 /*
242 * Maintain a "magic" minimum address. This keeps some older
243 * firmware platforms running.
244 */
245
246 if (claim_base < PROG_START)
247 claim_base = PROG_START;
248#endif
249
250 /* We need to claim the memsize plus the file offset since gzip
251 * will expand the header (file offset), then the kernel, then
252 * possible rubbish we don't care about. But the kernel bss must
253 * be claimed (it will be zero'd by the kernel itself)
254 */
255 printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
256 vmlinux.addr = try_claim(vmlinux.memsize);
257 if (vmlinux.addr == 0) {
258 printf("Can't allocate memory for kernel image !\n\r");
259 exit();
260 }
261
262 /*
263 * Now we try to claim memory for the initrd (and copy it there)
264 */
265 initrd.size = (unsigned long)(_initrd_end - _initrd_start);
266 initrd.memsize = initrd.size;
267 if ( initrd.size > 0 ) {
268 printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size);
269 initrd.addr = try_claim(initrd.size);
270 if (initrd.addr == 0) {
271 printf("Can't allocate memory for initial ramdisk !\n\r");
272 exit();
273 }
274 a1 = initrd.addr;
275 a2 = initrd.size;
276 printf("initial ramdisk moving 0x%lx <- 0x%lx (0x%lx bytes)\n\r",
277 initrd.addr, (unsigned long)_initrd_start, initrd.size);
278 memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
279 printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd.addr));
280 }
281
282 /* Eventually gunzip the kernel */
283 if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
284 printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
285 vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
286 len = vmlinuz.size;
287 gunzip((void *)vmlinux.addr, vmlinux.memsize,
288 (unsigned char *)vmlinuz.addr, &len);
289 printf("done 0x%lx bytes\n\r", len);
290 } else {
291 memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
292 }
293
294 /* Skip over the ELF header */
295#ifdef DEBUG
296 printf("... skipping 0x%lx bytes of ELF header\n\r",
297 elfoffset);
298#endif
299 vmlinux.addr += elfoffset;
300
301 flush_cache((void *)vmlinux.addr, vmlinux.size);
302
303 kernel_entry = (kernel_entry_t)vmlinux.addr;
304#ifdef DEBUG
305 printf( "kernel:\n\r"
306 " entry addr = 0x%lx\n\r"
307 " a1 = 0x%lx,\n\r"
308 " a2 = 0x%lx,\n\r"
309 " prom = 0x%lx,\n\r"
310 " bi_recs = 0x%lx,\n\r",
311 (unsigned long)kernel_entry, a1, a2,
312 (unsigned long)prom, NULL);
313#endif
314
315 kernel_entry(a1, a2, prom, NULL);
316
317 printf("Error: Linux kernel returned to zImage bootloader!\n\r");
318
319 exit();
320}
321
diff --git a/arch/powerpc/boot/page.h b/arch/powerpc/boot/page.h
new file mode 100644
index 000000000000..14eca30fef64
--- /dev/null
+++ b/arch/powerpc/boot/page.h
@@ -0,0 +1,34 @@
1#ifndef _PPC_BOOT_PAGE_H
2#define _PPC_BOOT_PAGE_H
3/*
4 * Copyright (C) 2001 PPC64 Team, IBM Corp
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#ifdef __ASSEMBLY__
13#define ASM_CONST(x) x
14#else
15#define __ASM_CONST(x) x##UL
16#define ASM_CONST(x) __ASM_CONST(x)
17#endif
18
19/* PAGE_SHIFT determines the page size */
20#define PAGE_SHIFT 12
21#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
22#define PAGE_MASK (~(PAGE_SIZE-1))
23
24/* align addr on a size boundary - adjust address up/down if needed */
25#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
26#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
27
28/* align addr on a size boundary - adjust address up if needed */
29#define _ALIGN(addr,size) _ALIGN_UP(addr,size)
30
31/* to align the pointer to the (next) page boundary */
32#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
33
34#endif /* _PPC_BOOT_PAGE_H */
diff --git a/arch/powerpc/boot/ppc_asm.h b/arch/powerpc/boot/ppc_asm.h
new file mode 100644
index 000000000000..1c2c2817f9b7
--- /dev/null
+++ b/arch/powerpc/boot/ppc_asm.h
@@ -0,0 +1,62 @@
1#ifndef _PPC64_PPC_ASM_H
2#define _PPC64_PPC_ASM_H
3/*
4 *
5 * Definitions used by various bits of low-level assembly code on PowerPC.
6 *
7 * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15/* Condition Register Bit Fields */
16
17#define cr0 0
18#define cr1 1
19#define cr2 2
20#define cr3 3
21#define cr4 4
22#define cr5 5
23#define cr6 6
24#define cr7 7
25
26
27/* General Purpose Registers (GPRs) */
28
29#define r0 0
30#define r1 1
31#define r2 2
32#define r3 3
33#define r4 4
34#define r5 5
35#define r6 6
36#define r7 7
37#define r8 8
38#define r9 9
39#define r10 10
40#define r11 11
41#define r12 12
42#define r13 13
43#define r14 14
44#define r15 15
45#define r16 16
46#define r17 17
47#define r18 18
48#define r19 19
49#define r20 20
50#define r21 21
51#define r22 22
52#define r23 23
53#define r24 24
54#define r25 25
55#define r26 26
56#define r27 27
57#define r28 28
58#define r29 29
59#define r30 30
60#define r31 31
61
62#endif /* _PPC64_PPC_ASM_H */
diff --git a/arch/powerpc/boot/prom.c b/arch/powerpc/boot/prom.c
new file mode 100644
index 000000000000..4bea2f4dcb06
--- /dev/null
+++ b/arch/powerpc/boot/prom.c
@@ -0,0 +1,499 @@
1/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9#include <stdarg.h>
10#include <stddef.h>
11#include "string.h"
12#include "stdio.h"
13#include "prom.h"
14
15int (*prom)(void *);
16
17void *chosen_handle;
18
19void *stdin;
20void *stdout;
21void *stderr;
22
23
24int
25write(void *handle, void *ptr, int nb)
26{
27 struct prom_args {
28 char *service;
29 int nargs;
30 int nret;
31 void *ihandle;
32 void *addr;
33 int len;
34 int actual;
35 } args;
36
37 args.service = "write";
38 args.nargs = 3;
39 args.nret = 1;
40 args.ihandle = handle;
41 args.addr = ptr;
42 args.len = nb;
43 args.actual = -1;
44 (*prom)(&args);
45 return args.actual;
46}
47
48int
49read(void *handle, void *ptr, int nb)
50{
51 struct prom_args {
52 char *service;
53 int nargs;
54 int nret;
55 void *ihandle;
56 void *addr;
57 int len;
58 int actual;
59 } args;
60
61 args.service = "read";
62 args.nargs = 3;
63 args.nret = 1;
64 args.ihandle = handle;
65 args.addr = ptr;
66 args.len = nb;
67 args.actual = -1;
68 (*prom)(&args);
69 return args.actual;
70}
71
72void
73exit()
74{
75 struct prom_args {
76 char *service;
77 } args;
78
79 for (;;) {
80 args.service = "exit";
81 (*prom)(&args);
82 }
83}
84
85void
86pause(void)
87{
88 struct prom_args {
89 char *service;
90 } args;
91
92 args.service = "enter";
93 (*prom)(&args);
94}
95
96void *
97finddevice(const char *name)
98{
99 struct prom_args {
100 char *service;
101 int nargs;
102 int nret;
103 const char *devspec;
104 void *phandle;
105 } args;
106
107 args.service = "finddevice";
108 args.nargs = 1;
109 args.nret = 1;
110 args.devspec = name;
111 args.phandle = (void *) -1;
112 (*prom)(&args);
113 return args.phandle;
114}
115
116void *
117claim(unsigned long virt, unsigned long size, unsigned long align)
118{
119 struct prom_args {
120 char *service;
121 int nargs;
122 int nret;
123 unsigned int virt;
124 unsigned int size;
125 unsigned int align;
126 void *ret;
127 } args;
128
129 args.service = "claim";
130 args.nargs = 3;
131 args.nret = 1;
132 args.virt = virt;
133 args.size = size;
134 args.align = align;
135 (*prom)(&args);
136 return args.ret;
137}
138
139int
140getprop(void *phandle, const char *name, void *buf, int buflen)
141{
142 struct prom_args {
143 char *service;
144 int nargs;
145 int nret;
146 void *phandle;
147 const char *name;
148 void *buf;
149 int buflen;
150 int size;
151 } args;
152
153 args.service = "getprop";
154 args.nargs = 4;
155 args.nret = 1;
156 args.phandle = phandle;
157 args.name = name;
158 args.buf = buf;
159 args.buflen = buflen;
160 args.size = -1;
161 (*prom)(&args);
162 return args.size;
163}
164
165int
166putc(int c, void *f)
167{
168 char ch = c;
169
170 if (c == '\n')
171 putc('\r', f);
172 return write(f, &ch, 1) == 1? c: -1;
173}
174
175int
176putchar(int c)
177{
178 return putc(c, stdout);
179}
180
181int
182fputs(char *str, void *f)
183{
184 int n = strlen(str);
185
186 return write(f, str, n) == n? 0: -1;
187}
188
189size_t strnlen(const char * s, size_t count)
190{
191 const char *sc;
192
193 for (sc = s; count-- && *sc != '\0'; ++sc)
194 /* nothing */;
195 return sc - s;
196}
197
198extern unsigned int __div64_32(unsigned long long *dividend,
199 unsigned int divisor);
200
201/* The unnecessary pointer compare is there
202 * to check for type safety (n must be 64bit)
203 */
204# define do_div(n,base) ({ \
205 unsigned int __base = (base); \
206 unsigned int __rem; \
207 (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \
208 if (((n) >> 32) == 0) { \
209 __rem = (unsigned int)(n) % __base; \
210 (n) = (unsigned int)(n) / __base; \
211 } else \
212 __rem = __div64_32(&(n), __base); \
213 __rem; \
214 })
215
216static int skip_atoi(const char **s)
217{
218 int i, c;
219
220 for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
221 i = i*10 + c - '0';
222 return i;
223}
224
225#define ZEROPAD 1 /* pad with zero */
226#define SIGN 2 /* unsigned/signed long */
227#define PLUS 4 /* show plus */
228#define SPACE 8 /* space if plus */
229#define LEFT 16 /* left justified */
230#define SPECIAL 32 /* 0x */
231#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
232
233static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
234{
235 char c,sign,tmp[66];
236 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
237 int i;
238
239 if (type & LARGE)
240 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
241 if (type & LEFT)
242 type &= ~ZEROPAD;
243 if (base < 2 || base > 36)
244 return 0;
245 c = (type & ZEROPAD) ? '0' : ' ';
246 sign = 0;
247 if (type & SIGN) {
248 if ((signed long long)num < 0) {
249 sign = '-';
250 num = - (signed long long)num;
251 size--;
252 } else if (type & PLUS) {
253 sign = '+';
254 size--;
255 } else if (type & SPACE) {
256 sign = ' ';
257 size--;
258 }
259 }
260 if (type & SPECIAL) {
261 if (base == 16)
262 size -= 2;
263 else if (base == 8)
264 size--;
265 }
266 i = 0;
267 if (num == 0)
268 tmp[i++]='0';
269 else while (num != 0) {
270 tmp[i++] = digits[do_div(num, base)];
271 }
272 if (i > precision)
273 precision = i;
274 size -= precision;
275 if (!(type&(ZEROPAD+LEFT)))
276 while(size-->0)
277 *str++ = ' ';
278 if (sign)
279 *str++ = sign;
280 if (type & SPECIAL) {
281 if (base==8)
282 *str++ = '0';
283 else if (base==16) {
284 *str++ = '0';
285 *str++ = digits[33];
286 }
287 }
288 if (!(type & LEFT))
289 while (size-- > 0)
290 *str++ = c;
291 while (i < precision--)
292 *str++ = '0';
293 while (i-- > 0)
294 *str++ = tmp[i];
295 while (size-- > 0)
296 *str++ = ' ';
297 return str;
298}
299
300int vsprintf(char *buf, const char *fmt, va_list args)
301{
302 int len;
303 unsigned long long num;
304 int i, base;
305 char * str;
306 const char *s;
307
308 int flags; /* flags to number() */
309
310 int field_width; /* width of output field */
311 int precision; /* min. # of digits for integers; max
312 number of chars for from string */
313 int qualifier; /* 'h', 'l', or 'L' for integer fields */
314 /* 'z' support added 23/7/1999 S.H. */
315 /* 'z' changed to 'Z' --davidm 1/25/99 */
316
317
318 for (str=buf ; *fmt ; ++fmt) {
319 if (*fmt != '%') {
320 *str++ = *fmt;
321 continue;
322 }
323
324 /* process flags */
325 flags = 0;
326 repeat:
327 ++fmt; /* this also skips first '%' */
328 switch (*fmt) {
329 case '-': flags |= LEFT; goto repeat;
330 case '+': flags |= PLUS; goto repeat;
331 case ' ': flags |= SPACE; goto repeat;
332 case '#': flags |= SPECIAL; goto repeat;
333 case '0': flags |= ZEROPAD; goto repeat;
334 }
335
336 /* get field width */
337 field_width = -1;
338 if ('0' <= *fmt && *fmt <= '9')
339 field_width = skip_atoi(&fmt);
340 else if (*fmt == '*') {
341 ++fmt;
342 /* it's the next argument */
343 field_width = va_arg(args, int);
344 if (field_width < 0) {
345 field_width = -field_width;
346 flags |= LEFT;
347 }
348 }
349
350 /* get the precision */
351 precision = -1;
352 if (*fmt == '.') {
353 ++fmt;
354 if ('0' <= *fmt && *fmt <= '9')
355 precision = skip_atoi(&fmt);
356 else if (*fmt == '*') {
357 ++fmt;
358 /* it's the next argument */
359 precision = va_arg(args, int);
360 }
361 if (precision < 0)
362 precision = 0;
363 }
364
365 /* get the conversion qualifier */
366 qualifier = -1;
367 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
368 qualifier = *fmt;
369 ++fmt;
370 }
371
372 /* default base */
373 base = 10;
374
375 switch (*fmt) {
376 case 'c':
377 if (!(flags & LEFT))
378 while (--field_width > 0)
379 *str++ = ' ';
380 *str++ = (unsigned char) va_arg(args, int);
381 while (--field_width > 0)
382 *str++ = ' ';
383 continue;
384
385 case 's':
386 s = va_arg(args, char *);
387 if (!s)
388 s = "<NULL>";
389
390 len = strnlen(s, precision);
391
392 if (!(flags & LEFT))
393 while (len < field_width--)
394 *str++ = ' ';
395 for (i = 0; i < len; ++i)
396 *str++ = *s++;
397 while (len < field_width--)
398 *str++ = ' ';
399 continue;
400
401 case 'p':
402 if (field_width == -1) {
403 field_width = 2*sizeof(void *);
404 flags |= ZEROPAD;
405 }
406 str = number(str,
407 (unsigned long) va_arg(args, void *), 16,
408 field_width, precision, flags);
409 continue;
410
411
412 case 'n':
413 if (qualifier == 'l') {
414 long * ip = va_arg(args, long *);
415 *ip = (str - buf);
416 } else if (qualifier == 'Z') {
417 size_t * ip = va_arg(args, size_t *);
418 *ip = (str - buf);
419 } else {
420 int * ip = va_arg(args, int *);
421 *ip = (str - buf);
422 }
423 continue;
424
425 case '%':
426 *str++ = '%';
427 continue;
428
429 /* integer number formats - set up the flags and "break" */
430 case 'o':
431 base = 8;
432 break;
433
434 case 'X':
435 flags |= LARGE;
436 case 'x':
437 base = 16;
438 break;
439
440 case 'd':
441 case 'i':
442 flags |= SIGN;
443 case 'u':
444 break;
445
446 default:
447 *str++ = '%';
448 if (*fmt)
449 *str++ = *fmt;
450 else
451 --fmt;
452 continue;
453 }
454 if (qualifier == 'l') {
455 num = va_arg(args, unsigned long);
456 if (flags & SIGN)
457 num = (signed long) num;
458 } else if (qualifier == 'Z') {
459 num = va_arg(args, size_t);
460 } else if (qualifier == 'h') {
461 num = (unsigned short) va_arg(args, int);
462 if (flags & SIGN)
463 num = (signed short) num;
464 } else {
465 num = va_arg(args, unsigned int);
466 if (flags & SIGN)
467 num = (signed int) num;
468 }
469 str = number(str, num, base, field_width, precision, flags);
470 }
471 *str = '\0';
472 return str-buf;
473}
474
475int sprintf(char * buf, const char *fmt, ...)
476{
477 va_list args;
478 int i;
479
480 va_start(args, fmt);
481 i=vsprintf(buf,fmt,args);
482 va_end(args);
483 return i;
484}
485
486static char sprint_buf[1024];
487
488int
489printf(const char *fmt, ...)
490{
491 va_list args;
492 int n;
493
494 va_start(args, fmt);
495 n = vsprintf(sprint_buf, fmt, args);
496 va_end(args);
497 write(stdout, sprint_buf, n);
498 return n;
499}
diff --git a/arch/powerpc/boot/prom.h b/arch/powerpc/boot/prom.h
new file mode 100644
index 000000000000..96ab5aec740c
--- /dev/null
+++ b/arch/powerpc/boot/prom.h
@@ -0,0 +1,18 @@
1#ifndef _PPC_BOOT_PROM_H_
2#define _PPC_BOOT_PROM_H_
3
4extern int (*prom) (void *);
5extern void *chosen_handle;
6
7extern void *stdin;
8extern void *stdout;
9extern void *stderr;
10
11extern int write(void *handle, void *ptr, int nb);
12extern int read(void *handle, void *ptr, int nb);
13extern void exit(void);
14extern void pause(void);
15extern void *finddevice(const char *);
16extern void *claim(unsigned long virt, unsigned long size, unsigned long align);
17extern int getprop(void *phandle, const char *name, void *buf, int buflen);
18#endif /* _PPC_BOOT_PROM_H_ */
diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
new file mode 100644
index 000000000000..24bd3a8dee94
--- /dev/null
+++ b/arch/powerpc/boot/stdio.h
@@ -0,0 +1,16 @@
1#ifndef _PPC_BOOT_STDIO_H_
2#define _PPC_BOOT_STDIO_H_
3
4extern int printf(const char *fmt, ...);
5
6extern int sprintf(char *buf, const char *fmt, ...);
7
8extern int vsprintf(char *buf, const char *fmt, va_list args);
9
10extern int putc(int c, void *f);
11extern int putchar(int c);
12extern int getchar(void);
13
14extern int fputs(char *str, void *f);
15
16#endif /* _PPC_BOOT_STDIO_H_ */
diff --git a/arch/powerpc/boot/string.S b/arch/powerpc/boot/string.S
new file mode 100644
index 000000000000..b1eeaed7db17
--- /dev/null
+++ b/arch/powerpc/boot/string.S
@@ -0,0 +1,216 @@
1/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * NOTE: this code runs in 32 bit mode and is packaged as ELF32.
10 */
11
12#include "ppc_asm.h"
13
14 .text
15 .globl strcpy
16strcpy:
17 addi r5,r3,-1
18 addi r4,r4,-1
191: lbzu r0,1(r4)
20 cmpwi 0,r0,0
21 stbu r0,1(r5)
22 bne 1b
23 blr
24
25 .globl strncpy
26strncpy:
27 cmpwi 0,r5,0
28 beqlr
29 mtctr r5
30 addi r6,r3,-1
31 addi r4,r4,-1
321: lbzu r0,1(r4)
33 cmpwi 0,r0,0
34 stbu r0,1(r6)
35 bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
36 blr
37
38 .globl strcat
39strcat:
40 addi r5,r3,-1
41 addi r4,r4,-1
421: lbzu r0,1(r5)
43 cmpwi 0,r0,0
44 bne 1b
45 addi r5,r5,-1
461: lbzu r0,1(r4)
47 cmpwi 0,r0,0
48 stbu r0,1(r5)
49 bne 1b
50 blr
51
52 .globl strcmp
53strcmp:
54 addi r5,r3,-1
55 addi r4,r4,-1
561: lbzu r3,1(r5)
57 cmpwi 1,r3,0
58 lbzu r0,1(r4)
59 subf. r3,r0,r3
60 beqlr 1
61 beq 1b
62 blr
63
64 .globl strlen
65strlen:
66 addi r4,r3,-1
671: lbzu r0,1(r4)
68 cmpwi 0,r0,0
69 bne 1b
70 subf r3,r3,r4
71 blr
72
73 .globl memset
74memset:
75 rlwimi r4,r4,8,16,23
76 rlwimi r4,r4,16,0,15
77 addi r6,r3,-4
78 cmplwi 0,r5,4
79 blt 7f
80 stwu r4,4(r6)
81 beqlr
82 andi. r0,r6,3
83 add r5,r0,r5
84 subf r6,r0,r6
85 rlwinm r0,r5,32-2,2,31
86 mtctr r0
87 bdz 6f
881: stwu r4,4(r6)
89 bdnz 1b
906: andi. r5,r5,3
917: cmpwi 0,r5,0
92 beqlr
93 mtctr r5
94 addi r6,r6,3
958: stbu r4,1(r6)
96 bdnz 8b
97 blr
98
99 .globl memmove
100memmove:
101 cmplw 0,r3,r4
102 bgt backwards_memcpy
103 /* fall through */
104
105 .globl memcpy
106memcpy:
107 rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */
108 addi r6,r3,-4
109 addi r4,r4,-4
110 beq 2f /* if less than 8 bytes to do */
111 andi. r0,r6,3 /* get dest word aligned */
112 mtctr r7
113 bne 5f
1141: lwz r7,4(r4)
115 lwzu r8,8(r4)
116 stw r7,4(r6)
117 stwu r8,8(r6)
118 bdnz 1b
119 andi. r5,r5,7
1202: cmplwi 0,r5,4
121 blt 3f
122 lwzu r0,4(r4)
123 addi r5,r5,-4
124 stwu r0,4(r6)
1253: cmpwi 0,r5,0
126 beqlr
127 mtctr r5
128 addi r4,r4,3
129 addi r6,r6,3
1304: lbzu r0,1(r4)
131 stbu r0,1(r6)
132 bdnz 4b
133 blr
1345: subfic r0,r0,4
135 mtctr r0
1366: lbz r7,4(r4)
137 addi r4,r4,1
138 stb r7,4(r6)
139 addi r6,r6,1
140 bdnz 6b
141 subf r5,r0,r5
142 rlwinm. r7,r5,32-3,3,31
143 beq 2b
144 mtctr r7
145 b 1b
146
147 .globl backwards_memcpy
148backwards_memcpy:
149 rlwinm. r7,r5,32-3,3,31 /* r7 = r5 >> 3 */
150 add r6,r3,r5
151 add r4,r4,r5
152 beq 2f
153 andi. r0,r6,3
154 mtctr r7
155 bne 5f
1561: lwz r7,-4(r4)
157 lwzu r8,-8(r4)
158 stw r7,-4(r6)
159 stwu r8,-8(r6)
160 bdnz 1b
161 andi. r5,r5,7
1622: cmplwi 0,r5,4
163 blt 3f
164 lwzu r0,-4(r4)
165 subi r5,r5,4
166 stwu r0,-4(r6)
1673: cmpwi 0,r5,0
168 beqlr
169 mtctr r5
1704: lbzu r0,-1(r4)
171 stbu r0,-1(r6)
172 bdnz 4b
173 blr
1745: mtctr r0
1756: lbzu r7,-1(r4)
176 stbu r7,-1(r6)
177 bdnz 6b
178 subf r5,r0,r5
179 rlwinm. r7,r5,32-3,3,31
180 beq 2b
181 mtctr r7
182 b 1b
183
184 .globl memcmp
185memcmp:
186 cmpwi 0,r5,0
187 blelr
188 mtctr r5
189 addi r6,r3,-1
190 addi r4,r4,-1
1911: lbzu r3,1(r6)
192 lbzu r0,1(r4)
193 subf. r3,r0,r3
194 bdnzt 2,1b
195 blr
196
197
198/*
199 * Flush the dcache and invalidate the icache for a range of addresses.
200 *
201 * flush_cache(addr, len)
202 */
203 .global flush_cache
204flush_cache:
205 addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
206 rlwinm. 4,4,27,5,31
207 mtctr 4
208 beqlr
2091: dcbf 0,3
210 icbi 0,3
211 addi 3,3,0x20
212 bdnz 1b
213 sync
214 isync
215 blr
216
diff --git a/arch/powerpc/boot/string.h b/arch/powerpc/boot/string.h
new file mode 100644
index 000000000000..9fdff1cc0d70
--- /dev/null
+++ b/arch/powerpc/boot/string.h
@@ -0,0 +1,17 @@
1#ifndef _PPC_BOOT_STRING_H_
2#define _PPC_BOOT_STRING_H_
3#include <stddef.h>
4
5extern char *strcpy(char *dest, const char *src);
6extern char *strncpy(char *dest, const char *src, size_t n);
7extern char *strcat(char *dest, const char *src);
8extern int strcmp(const char *s1, const char *s2);
9extern size_t strlen(const char *s);
10extern size_t strnlen(const char *s, size_t count);
11
12extern void *memset(void *s, int c, size_t n);
13extern void *memmove(void *dest, const void *src, unsigned long n);
14extern void *memcpy(void *dest, const void *src, unsigned long n);
15extern int memcmp(const void *s1, const void *s2, size_t n);
16
17#endif /* _PPC_BOOT_STRING_H_ */
diff --git a/arch/powerpc/boot/zImage.lds b/arch/powerpc/boot/zImage.lds
new file mode 100644
index 000000000000..4b6bb3ffe3dc
--- /dev/null
+++ b/arch/powerpc/boot/zImage.lds
@@ -0,0 +1,46 @@
1OUTPUT_ARCH(powerpc:common)
2ENTRY(_zimage_start)
3SECTIONS
4{
5 . = (4*1024*1024);
6 _start = .;
7 .text :
8 {
9 *(.text)
10 *(.fixup)
11 }
12 _etext = .;
13 . = ALIGN(4096);
14 .data :
15 {
16 *(.rodata*)
17 *(.data*)
18 *(.sdata*)
19 __got2_start = .;
20 *(.got2)
21 __got2_end = .;
22 }
23
24 . = ALIGN(4096);
25 _vmlinux_start = .;
26 .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
27 _vmlinux_end = .;
28
29 . = ALIGN(4096);
30 _initrd_start = .;
31 .kernel:initrd : { *(.kernel:initrd) }
32 _initrd_end = .;
33
34 . = ALIGN(4096);
35 _edata = .;
36
37 . = ALIGN(4096);
38 __bss_start = .;
39 .bss :
40 {
41 *(.sbss)
42 *(.bss)
43 }
44 . = ALIGN(4096);
45 _end = . ;
46}