aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-01-13 23:04:06 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-13 23:04:06 -0500
commit66a45dd3620ee5f913ba1af3d2dca8b9bdfa2b96 (patch)
treef98b25a1004d6e6bc84244186db61e76d5b2fe1c /arch/powerpc/boot
parent36874579dbf4cafa31486d4207c6807efbbf1378 (diff)
powerpc: Make COFF zImages for old 32-bit powermacs
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>
Diffstat (limited to 'arch/powerpc/boot')
-rw-r--r--arch/powerpc/boot/Makefile49
-rw-r--r--arch/powerpc/boot/crt0.S21
-rw-r--r--arch/powerpc/boot/hack-coff.c84
-rw-r--r--arch/powerpc/boot/main.c46
-rw-r--r--arch/powerpc/boot/prom.c538
-rw-r--r--arch/powerpc/boot/prom.h36
-rw-r--r--arch/powerpc/boot/rs6000.h243
-rw-r--r--arch/powerpc/boot/stdio.c325
-rw-r--r--arch/powerpc/boot/stdio.h6
-rw-r--r--arch/powerpc/boot/zImage.coff.lds46
10 files changed, 895 insertions, 499 deletions
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index b53d677f6742..788dec4c7ef3 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -25,8 +25,8 @@ HOSTCC := gcc
25BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \ 25BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
26 $(shell $(CROSS32CC) -print-file-name=include) -fPIC 26 $(shell $(CROSS32CC) -print-file-name=include) -fPIC
27BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc 27BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
28BOOTLFLAGS := -T $(srctree)/$(src)/zImage.lds
29OBJCOPYFLAGS := contents,alloc,load,readonly,data 28OBJCOPYFLAGS := contents,alloc,load,readonly,data
29OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
30 30
31zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c 31zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
32zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h 32zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
@@ -35,7 +35,7 @@ zliblinuxheader := zlib.h zconf.h zutil.h
35$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) 35$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
36#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h) 36#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
37 37
38src-boot := string.S prom.c main.c div64.S crt0.S 38src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
39src-boot += $(zlib) 39src-boot += $(zlib)
40src-boot := $(addprefix $(obj)/, $(src-boot)) 40src-boot := $(addprefix $(obj)/, $(src-boot))
41obj-boot := $(addsuffix .o, $(basename $(src-boot))) 41obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -70,7 +70,7 @@ quiet_cmd_bootas = BOOTAS $@
70 cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $< 70 cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
71 71
72quiet_cmd_bootld = BOOTLD $@ 72quiet_cmd_bootld = BOOTLD $@
73 cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2) 73 cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
74 74
75$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c 75$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
76 $(call if_changed_dep,bootcc) 76 $(call if_changed_dep,bootcc)
@@ -87,12 +87,14 @@ obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section)))
87src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) 87src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
88gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) 88gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
89 89
90hostprogs-y := addnote addRamDisk 90hostprogs-y := addnote addRamDisk hack-coff
91targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \ 91
92 $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ 92targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
93 $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ 93 zImage.coff zImage.initrd.coff \
94 $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ 94 $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
95 vmlinux.initrd 95 $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
96 $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
97 vmlinux.initrd
96extra-y := initrd.o 98extra-y := initrd.o
97 99
98quiet_cmd_ramdisk = RAMDISK $@ 100quiet_cmd_ramdisk = RAMDISK $@
@@ -114,6 +116,10 @@ quiet_cmd_addsection = ADDSEC $@
114quiet_cmd_addnote = ADDNOTE $@ 116quiet_cmd_addnote = ADDNOTE $@
115 cmd_addnote = $(obj)/addnote $@ 117 cmd_addnote = $(obj)/addnote $@
116 118
119quiet_cmd_gencoff = COFF $@
120 cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
121 $(obj)/hack-coff $@
122
117$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % 123$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
118 $(call if_changed,gzip) 124 $(call if_changed,gzip)
119 125
@@ -127,22 +133,35 @@ $(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
127 $(call if_changed_dep,bootcc) 133 $(call if_changed_dep,bootcc)
128 $(call cmd,addsection) 134 $(call cmd,addsection)
129 135
130$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required)) 136$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
131$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds 137$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
132 $(call cmd,bootld,$(obj-boot)) 138 $(call cmd,bootld,$(obj-boot),zImage.lds)
133 139
134$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd)) 140$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: obj-boot += $(call obj-sec, $(required) $(initrd))
135$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds 141$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
136 $(call cmd,bootld,$(obj-boot)) 142 $(call cmd,bootld,$(obj-boot),zImage.lds)
143
144# For 32-bit powermacs, build the COFF images as well as the ELF images.
145coffimage-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.coff
146coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.initrd.coff
137 147
138$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote 148$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y)
139 @cp -f $< $@ 149 @cp -f $< $@
140 $(call if_changed,addnote) 150 $(call if_changed,addnote)
141 151
142$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote 152$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote $(coffrdimg-y-y)
143 @cp -f $< $@ 153 @cp -f $< $@
144 $(call if_changed,addnote) 154 $(call if_changed,addnote)
145 155
156$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
157 $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
158 $(call cmd,gencoff)
159
160$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
161 $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
162 $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
163 $(call cmd,gencoff)
164
146#----------------------------------------------------------- 165#-----------------------------------------------------------
147# build u-boot images 166# build u-boot images
148#----------------------------------------------------------- 167#-----------------------------------------------------------
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index d2f2ace56cd3..e0192c26037b 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -12,17 +12,23 @@
12#include "ppc_asm.h" 12#include "ppc_asm.h"
13 13
14 .text 14 .text
15 /* a procedure descriptor used when booting this as a COFF file */
16_zimage_start_opd:
17 .long _zimage_start, 0, 0, 0
18
15 .globl _zimage_start 19 .globl _zimage_start
16_zimage_start: 20_zimage_start:
21 /* Work out the offset between the address we were linked at
22 and the address where we're running. */
17 bl 1f 23 bl 1f
18 241: mflr r0
191:
20 mflr r0
21 lis r9,1b@ha 25 lis r9,1b@ha
22 addi r9,r9,1b@l 26 addi r9,r9,1b@l
23 subf. r0,r9,r0 27 subf. r0,r9,r0
24 beq 3f 28 beq 3f /* if running at same address as linked */
25 29
30 /* The .got2 section contains a list of addresses, so add
31 the address offset onto each entry. */
26 lis r9,__got2_start@ha 32 lis r9,__got2_start@ha
27 addi r9,r9,__got2_start@l 33 addi r9,r9,__got2_start@l
28 lis r8,__got2_end@ha 34 lis r8,__got2_end@ha
@@ -32,15 +38,14 @@ _zimage_start:
32 srwi. r8,r8,2 38 srwi. r8,r8,2
33 mtctr r8 39 mtctr r8
34 add r9,r0,r9 40 add r9,r0,r9
352: 412: lwz r8,0(r9)
36 lwz r8,0(r9)
37 add r8,r8,r0 42 add r8,r8,r0
38 stw r8,0(r9) 43 stw r8,0(r9)
39 addi r9,r9,4 44 addi r9,r9,4
40 bdnz 2b 45 bdnz 2b
41 46
423: 47 /* Do a cache flush for our text, in case OF didn't */
43 lis r9,_start@h 483: lis r9,_start@h
44 add r9,r0,r9 49 add r9,r0,r9
45 lis r8,_etext@ha 50 lis r8,_etext@ha
46 addi r8,r8,_etext@l 51 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
index 000000000000..5e5a6573a1ef
--- /dev/null
+++ b/arch/powerpc/boot/hack-coff.c
@@ -0,0 +1,84 @@
1/*
2 * hack-coff.c - hack the header of an xcoff file to fill in
3 * a few fields needed by the Open Firmware xcoff loader on
4 * Power Macs but not initialized by objcopy.
5 *
6 * Copyright (C) Paul Mackerras 1997.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <string.h>
18#include "rs6000.h"
19
20#define AOUT_MAGIC 0x010b
21
22#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \
23 + ((unsigned char *)(x))[1])
24#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
25 ((unsigned char *)(x))[1] = (v) & 0xff)
26#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \
27 + (((unsigned char *)(x))[1] << 16) \
28 + (((unsigned char *)(x))[2] << 8) \
29 + ((unsigned char *)(x))[3])
30
31int
32main(int ac, char **av)
33{
34 int fd;
35 int i, nsect;
36 int aoutsz;
37 struct external_filehdr fhdr;
38 AOUTHDR aout;
39 struct external_scnhdr shdr;
40
41 if (ac != 2) {
42 fprintf(stderr, "Usage: hack-coff coff-file\n");
43 exit(1);
44 }
45 if ((fd = open(av[1], 2)) == -1) {
46 perror(av[2]);
47 exit(1);
48 }
49 if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
50 goto readerr;
51 i = get_16be(fhdr.f_magic);
52 if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
53 fprintf(stderr, "%s: not an xcoff file\n", av[1]);
54 exit(1);
55 }
56 aoutsz = get_16be(fhdr.f_opthdr);
57 if (read(fd, &aout, aoutsz) != aoutsz)
58 goto readerr;
59 nsect = get_16be(fhdr.f_nscns);
60 for (i = 0; i < nsect; ++i) {
61 if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
62 goto readerr;
63 if (strcmp(shdr.s_name, ".text") == 0) {
64 put_16be(aout.o_snentry, i+1);
65 put_16be(aout.o_sntext, i+1);
66 } else if (strcmp(shdr.s_name, ".data") == 0) {
67 put_16be(aout.o_sndata, i+1);
68 } else if (strcmp(shdr.s_name, ".bss") == 0) {
69 put_16be(aout.o_snbss, i+1);
70 }
71 }
72 put_16be(aout.magic, AOUT_MAGIC);
73 if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
74 || write(fd, &aout, aoutsz) != aoutsz) {
75 fprintf(stderr, "%s: write error\n", av[1]);
76 exit(1);
77 }
78 close(fd);
79 exit(0);
80
81readerr:
82 fprintf(stderr, "%s: read error or file too short\n", av[1]);
83 exit(1);
84}
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 64ec93116fa6..55ec59867250 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -21,8 +21,8 @@ extern void flush_cache(void *, unsigned long);
21 21
22 22
23/* Value picked to match that used by yaboot */ 23/* Value picked to match that used by yaboot */
24#define PROG_START 0x01400000 24#define PROG_START 0x01400000 /* only used on 64-bit systems */
25#define RAM_END (512<<20) // Fixme: use OF */ 25#define RAM_END (512<<20) /* Fixme: use OF */
26#define ONE_MB 0x100000 26#define ONE_MB 0x100000
27 27
28extern char _start[]; 28extern char _start[];
@@ -160,6 +160,17 @@ static int is_elf64(void *hdr)
160 elfoffset = (unsigned long)elf64ph->p_offset; 160 elfoffset = (unsigned long)elf64ph->p_offset;
161 vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset; 161 vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
162 vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset; 162 vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
163
164#if defined(PROG_START)
165 /*
166 * Maintain a "magic" minimum address. This keeps some older
167 * firmware platforms running.
168 */
169
170 if (claim_base < PROG_START)
171 claim_base = PROG_START;
172#endif
173
163 return 1; 174 return 1;
164} 175}
165 176
@@ -206,12 +217,18 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
206 exit(); 217 exit();
207 if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4) 218 if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
208 exit(); 219 exit();
209 stderr = stdout;
210 if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
211 exit();
212 220
213 printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp); 221 printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
214 222
223 /*
224 * The first available claim_base must be above the end of the
225 * the loaded kernel wrapper file (_start to _end includes the
226 * initrd image if it is present) and rounded up to a nice
227 * 1 MB boundary for good measure.
228 */
229
230 claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
231
215 vmlinuz.addr = (unsigned long)_vmlinux_start; 232 vmlinuz.addr = (unsigned long)_vmlinux_start;
216 vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); 233 vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
217 234
@@ -228,25 +245,6 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
228 exit(); 245 exit();
229 } 246 }
230 247
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 248 /* We need to claim the memsize plus the file offset since gzip
251 * will expand the header (file offset), then the kernel, then 249 * will expand the header (file offset), then the kernel, then
252 * possible rubbish we don't care about. But the kernel bss must 250 * possible rubbish we don't care about. But the kernel bss must
diff --git a/arch/powerpc/boot/prom.c b/arch/powerpc/boot/prom.c
index 4bea2f4dcb06..fa0057736f6b 100644
--- a/arch/powerpc/boot/prom.c
+++ b/arch/powerpc/boot/prom.c
@@ -13,487 +13,153 @@
13#include "prom.h" 13#include "prom.h"
14 14
15int (*prom)(void *); 15int (*prom)(void *);
16phandle chosen_handle;
17ihandle stdout;
16 18
17void *chosen_handle; 19int call_prom(const char *service, int nargs, int nret, ...)
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{ 20{
21 int i;
51 struct prom_args { 22 struct prom_args {
52 char *service; 23 const char *service;
53 int nargs; 24 int nargs;
54 int nret; 25 int nret;
55 void *ihandle; 26 unsigned int args[12];
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; 27 } args;
28 va_list list;
91 29
92 args.service = "enter"; 30 args.service = service;
93 (*prom)(&args); 31 args.nargs = nargs;
94} 32 args.nret = nret;
95 33
96void * 34 va_start(list, nret);
97finddevice(const char *name) 35 for (i = 0; i < nargs; i++)
98{ 36 args.args[i] = va_arg(list, unsigned int);
99 struct prom_args { 37 va_end(list);
100 char *service;
101 int nargs;
102 int nret;
103 const char *devspec;
104 void *phandle;
105 } args;
106 38
107 args.service = "finddevice"; 39 for (i = 0; i < nret; i++)
108 args.nargs = 1; 40 args.args[nargs+i] = 0;
109 args.nret = 1;
110 args.devspec = name;
111 args.phandle = (void *) -1;
112 (*prom)(&args);
113 return args.phandle;
114}
115 41
116void * 42 if (prom(&args) < 0)
117claim(unsigned long virt, unsigned long size, unsigned long align) 43 return -1;
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 44
129 args.service = "claim"; 45 return (nret > 0)? args.args[nargs]: 0;
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} 46}
138 47
139int 48int call_prom_ret(const char *service, int nargs, int nret,
140getprop(void *phandle, const char *name, void *buf, int buflen) 49 unsigned int *rets, ...)
141{ 50{
51 int i;
142 struct prom_args { 52 struct prom_args {
143 char *service; 53 const char *service;
144 int nargs; 54 int nargs;
145 int nret; 55 int nret;
146 void *phandle; 56 unsigned int args[12];
147 const char *name;
148 void *buf;
149 int buflen;
150 int size;
151 } args; 57 } args;
58 va_list list;
152 59
153 args.service = "getprop"; 60 args.service = service;
154 args.nargs = 4; 61 args.nargs = nargs;
155 args.nret = 1; 62 args.nret = nret;
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 63
165int 64 va_start(list, rets);
166putc(int c, void *f) 65 for (i = 0; i < nargs; i++)
167{ 66 args.args[i] = va_arg(list, unsigned int);
168 char ch = c; 67 va_end(list);
169 68
170 if (c == '\n') 69 for (i = 0; i < nret; i++)
171 putc('\r', f); 70 args.args[nargs+i] = 0;
172 return write(f, &ch, 1) == 1? c: -1;
173}
174 71
175int 72 if (prom(&args) < 0)
176putchar(int c) 73 return -1;
177{
178 return putc(c, stdout);
179}
180 74
181int 75 if (rets != (void *) 0)
182fputs(char *str, void *f) 76 for (i = 1; i < nret; ++i)
183{ 77 rets[i-1] = args.args[nargs+i];
184 int n = strlen(str);
185 78
186 return write(f, str, n) == n? 0: -1; 79 return (nret > 0)? args.args[nargs]: 0;
187} 80}
188 81
189size_t strnlen(const char * s, size_t count) 82int write(void *handle, void *ptr, int nb)
190{ 83{
191 const char *sc; 84 return call_prom("write", 3, 1, handle, ptr, nb);
192
193 for (sc = s; count-- && *sc != '\0'; ++sc)
194 /* nothing */;
195 return sc - s;
196} 85}
197 86
198extern unsigned int __div64_32(unsigned long long *dividend, 87/*
199 unsigned int divisor); 88 * Older OF's require that when claiming a specific range of addresses,
200 89 * we claim the physical space in the /memory node and the virtual
201/* The unnecessary pointer compare is there 90 * space in the chosen mmu node, and then do a map operation to
202 * to check for type safety (n must be 64bit) 91 * map virtual to physical.
203 */ 92 */
204# define do_div(n,base) ({ \ 93static int need_map = -1;
205 unsigned int __base = (base); \ 94static ihandle chosen_mmu;
206 unsigned int __rem; \ 95static phandle memory;
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 96
216static int skip_atoi(const char **s) 97/* returns true if s2 is a prefix of s1 */
98static int string_match(const char *s1, const char *s2)
217{ 99{
218 int i, c; 100 for (; *s2; ++s2)
219 101 if (*s1++ != *s2)
220 for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s) 102 return 0;
221 i = i*10 + c - '0'; 103 return 1;
222 return i;
223} 104}
224 105
225#define ZEROPAD 1 /* pad with zero */ 106static int check_of_version(void)
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{ 107{
235 char c,sign,tmp[66]; 108 phandle oprom, chosen;
236 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; 109 char version[64];
237 int i;
238 110
239 if (type & LARGE) 111 oprom = finddevice("/openprom");
240 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 112 if (oprom == (phandle) -1)
241 if (type & LEFT)
242 type &= ~ZEROPAD;
243 if (base < 2 || base > 36)
244 return 0; 113 return 0;
245 c = (type & ZEROPAD) ? '0' : ' '; 114 if (getprop(oprom, "model", version, sizeof(version)) <= 0)
246 sign = 0; 115 return 0;
247 if (type & SIGN) { 116 version[sizeof(version)-1] = 0;
248 if ((signed long long)num < 0) { 117 printf("OF version = '%s'\r\n", version);
249 sign = '-'; 118 if (!string_match(version, "Open Firmware, 1.")
250 num = - (signed long long)num; 119 && !string_match(version, "FirmWorks,3."))
251 size--; 120 return 0;
252 } else if (type & PLUS) { 121 chosen = finddevice("/chosen");
253 sign = '+'; 122 if (chosen == (phandle) -1) {
254 size--; 123 chosen = finddevice("/chosen@0");
255 } else if (type & SPACE) { 124 if (chosen == (phandle) -1) {
256 sign = ' '; 125 printf("no chosen\n");
257 size--; 126 return 0;
258 } 127 }
259 } 128 }
260 if (type & SPECIAL) { 129 if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
261 if (base == 16) 130 printf("no mmu\n");
262 size -= 2; 131 return 0;
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 } 132 }
272 if (i > precision) 133 memory = (ihandle) call_prom("open", 1, 1, "/memory");
273 precision = i; 134 if (memory == (ihandle) -1) {
274 size -= precision; 135 memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
275 if (!(type&(ZEROPAD+LEFT))) 136 if (memory == (ihandle) -1) {
276 while(size-->0) 137 printf("no memory node\n");
277 *str++ = ' '; 138 return 0;
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 } 139 }
287 } 140 }
288 if (!(type & LEFT)) 141 printf("old OF detected\r\n");
289 while (size-- > 0) 142 return 1;
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} 143}
299 144
300int vsprintf(char *buf, const char *fmt, va_list args) 145void *claim(unsigned long virt, unsigned long size, unsigned long align)
301{ 146{
302 int len; 147 int ret;
303 unsigned long long num; 148 unsigned int result;
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 149
150 if (need_map < 0)
151 need_map = check_of_version();
152 if (align || !need_map)
153 return (void *) call_prom("claim", 3, 1, virt, size, align);
317 154
318 for (str=buf ; *fmt ; ++fmt) { 155 ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
319 if (*fmt != '%') { 156 align, size, virt);
320 *str++ = *fmt; 157 if (ret != 0 || result == -1)
321 continue; 158 return (void *) -1;
322 } 159 ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
323 160 align, size, virt);
324 /* process flags */ 161 /* 0x12 == coherent + read/write */
325 flags = 0; 162 ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
326 repeat: 163 0x12, size, virt, virt);
327 ++fmt; /* this also skips first '%' */ 164 return (void *) virt;
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} 165}
diff --git a/arch/powerpc/boot/prom.h b/arch/powerpc/boot/prom.h
index 96ab5aec740c..3e2ddd4a5a81 100644
--- a/arch/powerpc/boot/prom.h
+++ b/arch/powerpc/boot/prom.h
@@ -1,18 +1,34 @@
1#ifndef _PPC_BOOT_PROM_H_ 1#ifndef _PPC_BOOT_PROM_H_
2#define _PPC_BOOT_PROM_H_ 2#define _PPC_BOOT_PROM_H_
3 3
4typedef void *phandle;
5typedef void *ihandle;
6
4extern int (*prom) (void *); 7extern int (*prom) (void *);
5extern void *chosen_handle; 8extern phandle chosen_handle;
9extern ihandle stdout;
6 10
7extern void *stdin; 11int call_prom(const char *service, int nargs, int nret, ...);
8extern void *stdout; 12int call_prom_ret(const char *service, int nargs, int nret,
9extern void *stderr; 13 unsigned int *rets, ...);
10 14
11extern int write(void *handle, void *ptr, int nb); 15extern int write(void *handle, void *ptr, int nb);
12extern int read(void *handle, void *ptr, int nb); 16extern void *claim(unsigned long virt, unsigned long size, unsigned long aln);
13extern void exit(void); 17
14extern void pause(void); 18static inline void exit(void)
15extern void *finddevice(const char *); 19{
16extern void *claim(unsigned long virt, unsigned long size, unsigned long align); 20 call_prom("exit", 0, 0);
17extern int getprop(void *phandle, const char *name, void *buf, int buflen); 21}
22
23static inline phandle finddevice(const char *name)
24{
25 return (phandle) call_prom("finddevice", 1, 1, name);
26}
27
28static inline int getprop(void *phandle, const char *name,
29 void *buf, int buflen)
30{
31 return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
32}
33
18#endif /* _PPC_BOOT_PROM_H_ */ 34#endif /* _PPC_BOOT_PROM_H_ */
diff --git a/arch/powerpc/boot/rs6000.h b/arch/powerpc/boot/rs6000.h
new file mode 100644
index 000000000000..433f45084e41
--- /dev/null
+++ b/arch/powerpc/boot/rs6000.h
@@ -0,0 +1,243 @@
1/* IBM RS/6000 "XCOFF" file definitions for BFD.
2 Copyright (C) 1990, 1991 Free Software Foundation, Inc.
3 FIXME: Can someone provide a transliteration of this name into ASCII?
4 Using the following chars caused a compiler warning on HIUX (so I replaced
5 them with octal escapes), and isn't useful without an understanding of what
6 character set it is.
7 Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
8 and John Gilmore of Cygnus Support. */
9
10/********************** FILE HEADER **********************/
11
12struct external_filehdr {
13 char f_magic[2]; /* magic number */
14 char f_nscns[2]; /* number of sections */
15 char f_timdat[4]; /* time & date stamp */
16 char f_symptr[4]; /* file pointer to symtab */
17 char f_nsyms[4]; /* number of symtab entries */
18 char f_opthdr[2]; /* sizeof(optional hdr) */
19 char f_flags[2]; /* flags */
20};
21
22 /* IBM RS/6000 */
23#define U802WRMAGIC 0730 /* writeable text segments **chh** */
24#define U802ROMAGIC 0735 /* readonly sharable text segments */
25#define U802TOCMAGIC 0737 /* readonly text segments and TOC */
26
27#define BADMAG(x) \
28 ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
29 (x).f_magic != U802TOCMAGIC)
30
31#define FILHDR struct external_filehdr
32#define FILHSZ 20
33
34
35/********************** AOUT "OPTIONAL HEADER" **********************/
36
37
38typedef struct
39{
40 unsigned char magic[2]; /* type of file */
41 unsigned char vstamp[2]; /* version stamp */
42 unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
43 unsigned char dsize[4]; /* initialized data " " */
44 unsigned char bsize[4]; /* uninitialized data " " */
45 unsigned char entry[4]; /* entry pt. */
46 unsigned char text_start[4]; /* base of text used for this file */
47 unsigned char data_start[4]; /* base of data used for this file */
48 unsigned char o_toc[4]; /* address of TOC */
49 unsigned char o_snentry[2]; /* section number of entry point */
50 unsigned char o_sntext[2]; /* section number of .text section */
51 unsigned char o_sndata[2]; /* section number of .data section */
52 unsigned char o_sntoc[2]; /* section number of TOC */
53 unsigned char o_snloader[2]; /* section number of .loader section */
54 unsigned char o_snbss[2]; /* section number of .bss section */
55 unsigned char o_algntext[2]; /* .text alignment */
56 unsigned char o_algndata[2]; /* .data alignment */
57 unsigned char o_modtype[2]; /* module type (??) */
58 unsigned char o_cputype[2]; /* cpu type */
59 unsigned char o_maxstack[4]; /* max stack size (??) */
60 unsigned char o_maxdata[4]; /* max data size (??) */
61 unsigned char o_resv2[12]; /* reserved */
62}
63AOUTHDR;
64
65#define AOUTSZ 72
66#define SMALL_AOUTSZ (28)
67#define AOUTHDRSZ 72
68
69#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */
70#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */
71#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */
72
73
74/********************** SECTION HEADER **********************/
75
76
77struct external_scnhdr {
78 char s_name[8]; /* section name */
79 char s_paddr[4]; /* physical address, aliased s_nlib */
80 char s_vaddr[4]; /* virtual address */
81 char s_size[4]; /* section size */
82 char s_scnptr[4]; /* file ptr to raw data for section */
83 char s_relptr[4]; /* file ptr to relocation */
84 char s_lnnoptr[4]; /* file ptr to line numbers */
85 char s_nreloc[2]; /* number of relocation entries */
86 char s_nlnno[2]; /* number of line number entries*/
87 char s_flags[4]; /* flags */
88};
89
90/*
91 * names of "special" sections
92 */
93#define _TEXT ".text"
94#define _DATA ".data"
95#define _BSS ".bss"
96#define _PAD ".pad"
97#define _LOADER ".loader"
98
99#define SCNHDR struct external_scnhdr
100#define SCNHSZ 40
101
102/* XCOFF uses a special .loader section with type STYP_LOADER. */
103#define STYP_LOADER 0x1000
104
105/* XCOFF uses a special .debug section with type STYP_DEBUG. */
106#define STYP_DEBUG 0x2000
107
108/* XCOFF handles line number or relocation overflow by creating
109 another section header with STYP_OVRFLO set. */
110#define STYP_OVRFLO 0x8000
111
112/********************** LINE NUMBERS **********************/
113
114/* 1 line number entry for every "breakpointable" source line in a section.
115 * Line numbers are grouped on a per function basis; first entry in a function
116 * grouping will have l_lnno = 0 and in place of physical address will be the
117 * symbol table index of the function name.
118 */
119struct external_lineno {
120 union {
121 char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
122 char l_paddr[4]; /* (physical) address of line number */
123 } l_addr;
124 char l_lnno[2]; /* line number */
125};
126
127
128#define LINENO struct external_lineno
129#define LINESZ 6
130
131
132/********************** SYMBOLS **********************/
133
134#define E_SYMNMLEN 8 /* # characters in a symbol name */
135#define E_FILNMLEN 14 /* # characters in a file name */
136#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
137
138struct external_syment
139{
140 union {
141 char e_name[E_SYMNMLEN];
142 struct {
143 char e_zeroes[4];
144 char e_offset[4];
145 } e;
146 } e;
147 char e_value[4];
148 char e_scnum[2];
149 char e_type[2];
150 char e_sclass[1];
151 char e_numaux[1];
152};
153
154
155
156#define N_BTMASK (017)
157#define N_TMASK (060)
158#define N_BTSHFT (4)
159#define N_TSHIFT (2)
160
161
162union external_auxent {
163 struct {
164 char x_tagndx[4]; /* str, un, or enum tag indx */
165 union {
166 struct {
167 char x_lnno[2]; /* declaration line number */
168 char x_size[2]; /* str/union/array size */
169 } x_lnsz;
170 char x_fsize[4]; /* size of function */
171 } x_misc;
172 union {
173 struct { /* if ISFCN, tag, or .bb */
174 char x_lnnoptr[4]; /* ptr to fcn line # */
175 char x_endndx[4]; /* entry ndx past block end */
176 } x_fcn;
177 struct { /* if ISARY, up to 4 dimen. */
178 char x_dimen[E_DIMNUM][2];
179 } x_ary;
180 } x_fcnary;
181 char x_tvndx[2]; /* tv index */
182 } x_sym;
183
184 union {
185 char x_fname[E_FILNMLEN];
186 struct {
187 char x_zeroes[4];
188 char x_offset[4];
189 } x_n;
190 } x_file;
191
192 struct {
193 char x_scnlen[4]; /* section length */
194 char x_nreloc[2]; /* # relocation entries */
195 char x_nlinno[2]; /* # line numbers */
196 } x_scn;
197
198 struct {
199 char x_tvfill[4]; /* tv fill value */
200 char x_tvlen[2]; /* length of .tv */
201 char x_tvran[2][2]; /* tv range */
202 } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
203
204 struct {
205 unsigned char x_scnlen[4];
206 unsigned char x_parmhash[4];
207 unsigned char x_snhash[2];
208 unsigned char x_smtyp[1];
209 unsigned char x_smclas[1];
210 unsigned char x_stab[4];
211 unsigned char x_snstab[2];
212 } x_csect;
213
214};
215
216#define SYMENT struct external_syment
217#define SYMESZ 18
218#define AUXENT union external_auxent
219#define AUXESZ 18
220#define DBXMASK 0x80 /* for dbx storage mask */
221#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
222
223
224
225/********************** RELOCATION DIRECTIVES **********************/
226
227
228struct external_reloc {
229 char r_vaddr[4];
230 char r_symndx[4];
231 char r_size[1];
232 char r_type[1];
233};
234
235
236#define RELOC struct external_reloc
237#define RELSZ 10
238
239#define DEFAULT_DATA_SECTION_ALIGNMENT 4
240#define DEFAULT_BSS_SECTION_ALIGNMENT 4
241#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
242/* For new sections we havn't heard of before */
243#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
new file mode 100644
index 000000000000..b5aa522f8b77
--- /dev/null
+++ b/arch/powerpc/boot/stdio.c
@@ -0,0 +1,325 @@
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
15size_t strnlen(const char * s, size_t count)
16{
17 const char *sc;
18
19 for (sc = s; count-- && *sc != '\0'; ++sc)
20 /* nothing */;
21 return sc - s;
22}
23
24extern unsigned int __div64_32(unsigned long long *dividend,
25 unsigned int divisor);
26
27/* The unnecessary pointer compare is there
28 * to check for type safety (n must be 64bit)
29 */
30# define do_div(n,base) ({ \
31 unsigned int __base = (base); \
32 unsigned int __rem; \
33 (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \
34 if (((n) >> 32) == 0) { \
35 __rem = (unsigned int)(n) % __base; \
36 (n) = (unsigned int)(n) / __base; \
37 } else \
38 __rem = __div64_32(&(n), __base); \
39 __rem; \
40 })
41
42static int skip_atoi(const char **s)
43{
44 int i, c;
45
46 for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
47 i = i*10 + c - '0';
48 return i;
49}
50
51#define ZEROPAD 1 /* pad with zero */
52#define SIGN 2 /* unsigned/signed long */
53#define PLUS 4 /* show plus */
54#define SPACE 8 /* space if plus */
55#define LEFT 16 /* left justified */
56#define SPECIAL 32 /* 0x */
57#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
58
59static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
60{
61 char c,sign,tmp[66];
62 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
63 int i;
64
65 if (type & LARGE)
66 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
67 if (type & LEFT)
68 type &= ~ZEROPAD;
69 if (base < 2 || base > 36)
70 return 0;
71 c = (type & ZEROPAD) ? '0' : ' ';
72 sign = 0;
73 if (type & SIGN) {
74 if ((signed long long)num < 0) {
75 sign = '-';
76 num = - (signed long long)num;
77 size--;
78 } else if (type & PLUS) {
79 sign = '+';
80 size--;
81 } else if (type & SPACE) {
82 sign = ' ';
83 size--;
84 }
85 }
86 if (type & SPECIAL) {
87 if (base == 16)
88 size -= 2;
89 else if (base == 8)
90 size--;
91 }
92 i = 0;
93 if (num == 0)
94 tmp[i++]='0';
95 else while (num != 0) {
96 tmp[i++] = digits[do_div(num, base)];
97 }
98 if (i > precision)
99 precision = i;
100 size -= precision;
101 if (!(type&(ZEROPAD+LEFT)))
102 while(size-->0)
103 *str++ = ' ';
104 if (sign)
105 *str++ = sign;
106 if (type & SPECIAL) {
107 if (base==8)
108 *str++ = '0';
109 else if (base==16) {
110 *str++ = '0';
111 *str++ = digits[33];
112 }
113 }
114 if (!(type & LEFT))
115 while (size-- > 0)
116 *str++ = c;
117 while (i < precision--)
118 *str++ = '0';
119 while (i-- > 0)
120 *str++ = tmp[i];
121 while (size-- > 0)
122 *str++ = ' ';
123 return str;
124}
125
126int vsprintf(char *buf, const char *fmt, va_list args)
127{
128 int len;
129 unsigned long long num;
130 int i, base;
131 char * str;
132 const char *s;
133
134 int flags; /* flags to number() */
135
136 int field_width; /* width of output field */
137 int precision; /* min. # of digits for integers; max
138 number of chars for from string */
139 int qualifier; /* 'h', 'l', or 'L' for integer fields */
140 /* 'z' support added 23/7/1999 S.H. */
141 /* 'z' changed to 'Z' --davidm 1/25/99 */
142
143
144 for (str=buf ; *fmt ; ++fmt) {
145 if (*fmt != '%') {
146 *str++ = *fmt;
147 continue;
148 }
149
150 /* process flags */
151 flags = 0;
152 repeat:
153 ++fmt; /* this also skips first '%' */
154 switch (*fmt) {
155 case '-': flags |= LEFT; goto repeat;
156 case '+': flags |= PLUS; goto repeat;
157 case ' ': flags |= SPACE; goto repeat;
158 case '#': flags |= SPECIAL; goto repeat;
159 case '0': flags |= ZEROPAD; goto repeat;
160 }
161
162 /* get field width */
163 field_width = -1;
164 if ('0' <= *fmt && *fmt <= '9')
165 field_width = skip_atoi(&fmt);
166 else if (*fmt == '*') {
167 ++fmt;
168 /* it's the next argument */
169 field_width = va_arg(args, int);
170 if (field_width < 0) {
171 field_width = -field_width;
172 flags |= LEFT;
173 }
174 }
175
176 /* get the precision */
177 precision = -1;
178 if (*fmt == '.') {
179 ++fmt;
180 if ('0' <= *fmt && *fmt <= '9')
181 precision = skip_atoi(&fmt);
182 else if (*fmt == '*') {
183 ++fmt;
184 /* it's the next argument */
185 precision = va_arg(args, int);
186 }
187 if (precision < 0)
188 precision = 0;
189 }
190
191 /* get the conversion qualifier */
192 qualifier = -1;
193 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
194 qualifier = *fmt;
195 ++fmt;
196 }
197
198 /* default base */
199 base = 10;
200
201 switch (*fmt) {
202 case 'c':
203 if (!(flags & LEFT))
204 while (--field_width > 0)
205 *str++ = ' ';
206 *str++ = (unsigned char) va_arg(args, int);
207 while (--field_width > 0)
208 *str++ = ' ';
209 continue;
210
211 case 's':
212 s = va_arg(args, char *);
213 if (!s)
214 s = "<NULL>";
215
216 len = strnlen(s, precision);
217
218 if (!(flags & LEFT))
219 while (len < field_width--)
220 *str++ = ' ';
221 for (i = 0; i < len; ++i)
222 *str++ = *s++;
223 while (len < field_width--)
224 *str++ = ' ';
225 continue;
226
227 case 'p':
228 if (field_width == -1) {
229 field_width = 2*sizeof(void *);
230 flags |= ZEROPAD;
231 }
232 str = number(str,
233 (unsigned long) va_arg(args, void *), 16,
234 field_width, precision, flags);
235 continue;
236
237
238 case 'n':
239 if (qualifier == 'l') {
240 long * ip = va_arg(args, long *);
241 *ip = (str - buf);
242 } else if (qualifier == 'Z') {
243 size_t * ip = va_arg(args, size_t *);
244 *ip = (str - buf);
245 } else {
246 int * ip = va_arg(args, int *);
247 *ip = (str - buf);
248 }
249 continue;
250
251 case '%':
252 *str++ = '%';
253 continue;
254
255 /* integer number formats - set up the flags and "break" */
256 case 'o':
257 base = 8;
258 break;
259
260 case 'X':
261 flags |= LARGE;
262 case 'x':
263 base = 16;
264 break;
265
266 case 'd':
267 case 'i':
268 flags |= SIGN;
269 case 'u':
270 break;
271
272 default:
273 *str++ = '%';
274 if (*fmt)
275 *str++ = *fmt;
276 else
277 --fmt;
278 continue;
279 }
280 if (qualifier == 'l') {
281 num = va_arg(args, unsigned long);
282 if (flags & SIGN)
283 num = (signed long) num;
284 } else if (qualifier == 'Z') {
285 num = va_arg(args, size_t);
286 } else if (qualifier == 'h') {
287 num = (unsigned short) va_arg(args, int);
288 if (flags & SIGN)
289 num = (signed short) num;
290 } else {
291 num = va_arg(args, unsigned int);
292 if (flags & SIGN)
293 num = (signed int) num;
294 }
295 str = number(str, num, base, field_width, precision, flags);
296 }
297 *str = '\0';
298 return str-buf;
299}
300
301int sprintf(char * buf, const char *fmt, ...)
302{
303 va_list args;
304 int i;
305
306 va_start(args, fmt);
307 i=vsprintf(buf,fmt,args);
308 va_end(args);
309 return i;
310}
311
312static char sprint_buf[1024];
313
314int
315printf(const char *fmt, ...)
316{
317 va_list args;
318 int n;
319
320 va_start(args, fmt);
321 n = vsprintf(sprint_buf, fmt, args);
322 va_end(args);
323 write(stdout, sprint_buf, n);
324 return n;
325}
diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
index 24bd3a8dee94..eb9e16c87aef 100644
--- a/arch/powerpc/boot/stdio.h
+++ b/arch/powerpc/boot/stdio.h
@@ -7,10 +7,4 @@ extern int sprintf(char *buf, const char *fmt, ...);
7 7
8extern int vsprintf(char *buf, const char *fmt, va_list args); 8extern int vsprintf(char *buf, const char *fmt, va_list args);
9 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_ */ 10#endif /* _PPC_BOOT_STDIO_H_ */
diff --git a/arch/powerpc/boot/zImage.coff.lds b/arch/powerpc/boot/zImage.coff.lds
new file mode 100644
index 000000000000..6016251a1a2c
--- /dev/null
+++ b/arch/powerpc/boot/zImage.coff.lds
@@ -0,0 +1,46 @@
1OUTPUT_ARCH(powerpc:common)
2ENTRY(_start)
3SECTIONS
4{
5 . = (5*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 _vmlinux_start = .;
24 *(.kernel:vmlinux.strip)
25 _vmlinux_end = .;
26
27 _initrd_start = .;
28 *(.kernel:initrd)
29 _initrd_end = .;
30 }
31
32 . = ALIGN(4096);
33 _edata = .;
34 __bss_start = .;
35 .bss :
36 {
37 *(.sbss)
38 *(.bss)
39 }
40 _end = . ;
41
42 /DISCARD/ :
43 {
44 *(.comment)
45 }
46}