1
2
3
4
5
6
7
8
9
10
11#define __KERNEL__
12#include "ppc32-types.h"
13#include "zlib.h"
14#include <linux/elf.h>
15#include <asm/processor.h>
16#include <asm/page.h>
17#include <asm/bootinfo.h>
18
19void memmove(void *dst, void *im, int len);
20void *memcpy(void *dest, const void *src, size_t n);
21size_t strlen(const char *s);
22
23extern void *finddevice(const char *);
24extern int getprop(void *, const char *, void *, int);
25extern void printk(char *fmt, ...);
26extern void printf(const char *fmt, ...);
27extern int sprintf(char *buf, const char *fmt, ...);
28void gunzip(void *, int, unsigned char *, int *);
29void *claim(unsigned int, unsigned int, unsigned int);
30void flush_cache(void *, unsigned long);
31void pause(void);
32extern void exit(void);
33
34static struct bi_record *make_bi_recs(unsigned long);
35
36#define RAM_START 0x00000000
37#define RAM_END (64<<20)
38
39
40#define PROG_START 0x01400000
41
42char *avail_ram;
43char *begin_avail, *end_avail;
44char *avail_high;
45unsigned int heap_use;
46unsigned int heap_max;
47
48extern char _end[];
49extern char _vmlinux_start[];
50extern char _vmlinux_end[];
51extern char _sysmap_start[];
52extern char _sysmap_end[];
53extern char _initrd_start[];
54extern char _initrd_end[];
55
56extern void *_vmlinux_filesize;
57extern void *_vmlinux_memsize;
58
59struct addr_range {
60 unsigned long addr;
61 unsigned long size;
62 unsigned long memsize;
63};
64struct addr_range vmlinux = {0, 0, 0};
65struct addr_range vmlinuz = {0, 0, 0};
66struct addr_range sysmap = {0, 0, 0};
67struct addr_range initrd = {0, 0, 0};
68
69static char scratch[128<<10];
70
71typedef void (*kernel_entry_t)( unsigned long,
72 unsigned long,
73 void *,
74 struct bi_record *);
75
76
77int (*prom)(void *);
78
79void *chosen_handle;
80void *stdin;
81void *stdout;
82void *stderr;
83
84
85void
86start(unsigned long a1, unsigned long a2, void *promptr)
87{
88 unsigned long i, claim_addr, claim_size;
89 unsigned long vmlinux_filesize;
90 extern char _start;
91 struct bi_record *bi_recs;
92 kernel_entry_t kernel_entry;
93 Elf64_Ehdr *elf64;
94 Elf64_Phdr *elf64ph;
95
96 prom = (int (*)(void *)) promptr;
97 chosen_handle = finddevice("/chosen");
98 if (chosen_handle == (void *) -1)
99 exit();
100 if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
101 exit();
102 stderr = stdout;
103 if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
104 exit();
105
106 printf("\n\rzImage starting: loaded at 0x%x\n\r", (unsigned)&_start);
107
108 initrd.size = (unsigned long)(_initrd_end - _initrd_start);
109 initrd.memsize = initrd.size;
110 if ( initrd.size > 0 ) {
111 initrd.addr = (RAM_END - initrd.size) & ~0xFFF;
112 a1 = a2 = 0;
113 claim(initrd.addr, RAM_END - initrd.addr, 0);
114 printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r",
115 initrd.addr, (unsigned long)_initrd_start, initrd.size);
116 memcpy((void *)initrd.addr, (void *)_initrd_start, initrd.size);
117 }
118
119 vmlinuz.addr = (unsigned long)_vmlinux_start;
120 vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
121 vmlinux.addr = (unsigned long)(void *)-1;
122 vmlinux_filesize = (unsigned long)&_vmlinux_filesize;
123 vmlinux.size = PAGE_ALIGN(vmlinux_filesize);
124 vmlinux.memsize = (unsigned long)&_vmlinux_memsize;
125
126 claim_size = vmlinux.memsize ;
127 for(claim_addr = PROG_START;
128 claim_addr <= PROG_START * 8;
129 claim_addr += 0x100000) {
130 printf(" trying: 0x%08lx\n\r", claim_addr);
131 vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0);
132 if ((void *)vmlinux.addr != (void *)-1) break;
133 }
134 if ((void *)vmlinux.addr == (void *)-1) {
135 printf("claim error, can't allocate kernel memory\n\r");
136 exit();
137 }
138
139
140 if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
141 avail_ram = scratch;
142 begin_avail = avail_high = avail_ram;
143 end_avail = scratch + sizeof(scratch);
144 printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
145 vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
146 gunzip((void *)vmlinux.addr, vmlinux.size,
147 (unsigned char *)vmlinuz.addr, (int *)&vmlinuz.size);
148 printf("done %lu bytes\n\r", vmlinuz.size);
149 printf("%u bytes of heap consumed, max in use %u\n\r",
150 (unsigned)(avail_high - begin_avail), heap_max);
151 } else {
152 memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size);
153 }
154
155
156 elf64 = (Elf64_Ehdr *)vmlinux.addr;
157 if ( elf64->e_ident[EI_MAG0] != ELFMAG0 ||
158 elf64->e_ident[EI_MAG1] != ELFMAG1 ||
159 elf64->e_ident[EI_MAG2] != ELFMAG2 ||
160 elf64->e_ident[EI_MAG3] != ELFMAG3 ||
161 elf64->e_ident[EI_CLASS] != ELFCLASS64 ||
162 elf64->e_ident[EI_DATA] != ELFDATA2MSB ||
163 elf64->e_type != ET_EXEC ||
164 elf64->e_machine != EM_PPC64 )
165 {
166 printf("Error: not a valid PPC64 ELF file!\n\r");
167 exit();
168 }
169
170 elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
171 (unsigned long)elf64->e_phoff);
172 for(i=0; i < (unsigned int)elf64->e_phnum ;i++,elf64ph++) {
173 if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0)
174 break;
175 }
176 printf("... skipping 0x%lx bytes of ELF header\n\r",
177 (unsigned long)elf64ph->p_offset);
178 vmlinux.addr += (unsigned long)elf64ph->p_offset;
179 vmlinux.size -= (unsigned long)elf64ph->p_offset;
180
181 flush_cache((void *)vmlinux.addr, vmlinux.memsize);
182
183 bi_recs = make_bi_recs(vmlinux.addr + vmlinux.memsize);
184
185 kernel_entry = (kernel_entry_t)vmlinux.addr;
186 printf( "kernel:\n\r"
187 " entry addr = 0x%lx\n\r"
188 " a1 = 0x%lx,\n\r"
189 " a2 = 0x%lx,\n\r"
190 " prom = 0x%lx,\n\r"
191 " bi_recs = 0x%lx,\n\r",
192 (unsigned long)kernel_entry, a1, a2,
193 (unsigned long)prom, (unsigned long)bi_recs);
194
195 kernel_entry( a1, a2, prom, bi_recs );
196
197 printf("Error: Linux kernel returned to zImage bootloader!\n\r");
198
199 exit();
200}
201
202static struct bi_record *
203make_bi_recs(unsigned long addr)
204{
205 struct bi_record *bi_recs;
206 struct bi_record *rec;
207
208 bi_recs = rec = bi_rec_init(addr);
209
210 rec = bi_rec_alloc(rec, 2);
211 rec->tag = BI_FIRST;
212
213
214
215 rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1);
216 rec->tag = BI_BOOTLOADER_ID;
217 sprintf( (char *)rec->data, "chrpboot");
218
219 rec = bi_rec_alloc(rec, 2);
220 rec->tag = BI_MACHTYPE;
221 rec->data[0] = PLATFORM_PSERIES;
222 rec->data[1] = 1;
223
224 if ( initrd.size > 0 ) {
225 rec = bi_rec_alloc(rec, 2);
226 rec->tag = BI_INITRD;
227 rec->data[0] = initrd.addr;
228 rec->data[1] = initrd.size;
229 }
230
231 if ( sysmap.size > 0 ) {
232 rec = bi_rec_alloc(rec, 2);
233 rec->tag = BI_SYSMAP;
234 rec->data[0] = (unsigned long)sysmap.addr;
235 rec->data[1] = (unsigned long)sysmap.size;
236 }
237
238 rec = bi_rec_alloc(rec, 1);
239 rec->tag = BI_LAST;
240 rec->data[0] = (bi_rec_field)bi_recs;
241
242
243
244
245 bi_recs->data[0] = (bi_rec_field)rec;
246 bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs;
247
248 return bi_recs;
249}
250
251struct memchunk {
252 unsigned int size;
253 unsigned int pad;
254 struct memchunk *next;
255};
256
257static struct memchunk *freechunks;
258
259void *zalloc(void *x, unsigned items, unsigned size)
260{
261 void *p;
262 struct memchunk **mpp, *mp;
263
264 size *= items;
265 size = _ALIGN(size, sizeof(struct memchunk));
266 heap_use += size;
267 if (heap_use > heap_max)
268 heap_max = heap_use;
269 for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) {
270 if (mp->size == size) {
271 *mpp = mp->next;
272 return mp;
273 }
274 }
275 p = avail_ram;
276 avail_ram += size;
277 if (avail_ram > avail_high)
278 avail_high = avail_ram;
279 if (avail_ram > end_avail) {
280 printf("oops... out of memory\n\r");
281 pause();
282 }
283 return p;
284}
285
286void zfree(void *x, void *addr, unsigned nb)
287{
288 struct memchunk *mp = addr;
289
290 nb = _ALIGN(nb, sizeof(struct memchunk));
291 heap_use -= nb;
292 if (avail_ram == addr + nb) {
293 avail_ram = addr;
294 return;
295 }
296 mp->size = nb;
297 mp->next = freechunks;
298 freechunks = mp;
299}
300
301#define HEAD_CRC 2
302#define EXTRA_FIELD 4
303#define ORIG_NAME 8
304#define COMMENT 0x10
305#define RESERVED 0xe0
306
307#define DEFLATED 8
308
309void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
310{
311 z_stream s;
312 int r, i, flags;
313
314
315 i = 10;
316 flags = src[3];
317 if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
318 printf("bad gzipped data\n\r");
319 exit();
320 }
321 if ((flags & EXTRA_FIELD) != 0)
322 i = 12 + src[10] + (src[11] << 8);
323 if ((flags & ORIG_NAME) != 0)
324 while (src[i++] != 0)
325 ;
326 if ((flags & COMMENT) != 0)
327 while (src[i++] != 0)
328 ;
329 if ((flags & HEAD_CRC) != 0)
330 i += 2;
331 if (i >= *lenp) {
332 printf("gunzip: ran out of data in header\n\r");
333 exit();
334 }
335
336 s.zalloc = zalloc;
337 s.zfree = zfree;
338 r = inflateInit2(&s, -MAX_WBITS);
339 if (r != Z_OK) {
340 printf("inflateInit2 returned %d\n\r", r);
341 exit();
342 }
343 s.next_in = src + i;
344 s.avail_in = *lenp - i;
345 s.next_out = dst;
346 s.avail_out = dstlen;
347 r = inflate(&s, Z_FINISH);
348 if (r != Z_OK && r != Z_STREAM_END) {
349 printf("inflate returned %d msg: %s\n\r", r, s.msg);
350 exit();
351 }
352 *lenp = s.next_out - (unsigned char *) dst;
353 inflateEnd(&s);
354}
355
356