main.c revision 1.26.4.1 1 /*
2 * $NetBSD: main.c,v 1.26.4.1 2011/02/08 16:19:11 bouyer Exp $
3 *
4 *
5 * Copyright (c) 1996,1999 Ignatios Souvatzis
6 * Copyright (c) 1994 Michael L. Hitch
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31 #include <sys/cdefs.h>
32 #include <sys/reboot.h>
33 #include <sys/types.h>
34
35 #include <sys/exec_aout.h>
36
37 #include <amiga/cfdev.h>
38 #include <amiga/memlist.h>
39 #include <include/cpu.h>
40
41 #include <saerrno.h>
42 #include <lib/libsa/stand.h>
43
44 #include "libstubs.h"
45 #include "samachdep.h"
46 #include "loadfile.h"
47
48 #undef AOUT_LDPGSZ
49 #define AOUT_LDPGSZ 8192
50 #define __PGSZ 8192
51
52 #define DRACOREVISION (*(u_int8_t *)0x02000009)
53 #define DRACOMMUMARGIN 0x200000
54 #define DRACOZ2OFFSET 0x3000000
55 #define DRACOZ2MAX 0x1000000
56
57 #define EXECMIN 36
58
59 /*
60 * vers.c (generated by newvers.sh)
61 */
62 extern const char bootprog_rev[];
63
64 void startit(void *, u_long, u_long, void *, u_long, u_long, int, void *,
65 int, int, u_long, u_long, u_long, int);
66 int get_cpuid(u_int32_t *);
67 #ifdef PPCBOOTER
68 u_int16_t kickstart[];
69 size_t kicksize;
70 #else
71 void startit_end(void);
72 #endif
73
74 /*
75 * Kernel startup interface version
76 * 1: first version of loadbsd
77 * 2: needs esym location passed in a4
78 * 3: load kernel image into fastmem rather than chipmem
79 * MAX: highest version with backward compatibility.
80 */
81
82 #define KERNEL_STARTUP_VERSION 3
83 #define KERNEL_STARTUP_VERSION_MAX 9
84
85 static long get_number(char **);
86
87 extern char default_command[];
88
89 int
90 pain(void *aio, void *cons)
91 {
92 char linebuf[128];
93 char *kernel_name = default_command;
94 char *path = default_command;
95 int boothowto = RB_AUTOBOOT;
96 u_int32_t cpuid = 0;
97 int amiga_flags = 0;
98 u_int32_t I_flag = 0;
99 int k_flag = 0;
100 int p_flag = 0;
101 int m_value = 0;
102 int S_flag = 0;
103 int t_flag = 0;
104
105 u_int32_t fmem = 0x0;
106 int fmemsz = 0x0;
107 int cmemsz = 0x0;
108 int eclock = SysBase->EClockFreq;
109 /* int skip_chipmem = 0; */
110
111 void (*start_it)(void *, u_long, u_long, void *, u_long, u_long, int,
112 void *, int, int, u_long, u_long, u_long, int);
113
114 void *kp;
115 u_int16_t *kvers;
116 int ksize;
117 void *esym = 0;
118 int32_t *nkcd;
119 struct cfdev *cd, *kcd;
120 struct boot_memseg *kmemseg;
121 struct boot_memseg *memseg;
122 struct MemHead *mh;
123 u_int32_t from, size, vfrom, vsize;
124 int contflag, mapped1to1;
125
126 int ncd, nseg;
127 char c;
128
129 u_long marks[MARK_MAX];
130
131 extern u_int16_t timelimit;
132
133 extern u_int32_t aio_base;
134
135 xdinit(aio);
136
137 if (consinit(cons))
138 return(1);
139
140 /*
141 * we need V36 for: EClock, RDB Bootblocks, CacheClearU
142 */
143
144 if (SysBase->LibNode.Version < EXECMIN) {
145 printf("Exec V%ld, need V%ld\n",
146 (long)SysBase->LibNode.Version, (long)EXECMIN);
147 goto out;
148 }
149
150 /*
151 * XXX Do this differently; default boot will attempt to load a list of
152 * XXX kernels until one of them succeeds.
153 */
154 timelimit = 3;
155 again:
156 #ifdef PPCBOOTER
157 printf("\nNetBSD/AmigaPPC " NETBSD_VERS " Bootstrap, Revision %s\n",
158 bootprog_rev);
159 #else
160 printf("\nNetBSD/Amiga " NETBSD_VERS " Bootstrap, Revision %s\n",
161 bootprog_rev);
162 #endif
163 printf("\n");
164 printf("Boot: [%s] ", kernel_name);
165
166 gets(linebuf);
167
168 if (*linebuf == 'q')
169 return 1;
170
171 if (*linebuf)
172 path = linebuf;
173
174 /*
175 * parse boot command for path name and process any options
176 */
177 while ((c = *path)) {
178 while (c == ' ')
179 c = *++path;
180 if (c == '-') {
181 while ((c = *++path) && c != ' ') {
182 switch (c) {
183 case 'a': /* multi-user state */
184 boothowto &= ~RB_SINGLE;
185 break;
186 case 'b': /* ask for root device */
187 boothowto |= RB_ASKNAME;
188 break;
189 case 'c': /* force machine model */
190 cpuid = get_number(&path) << 16;
191 break;
192 case 'k': /* Reserve first 4M fastmem */
193 k_flag++;
194 break;
195 case 'm': /* Force fastmem size */
196 m_value = get_number(&path) * 1024;
197 break;
198 case 'n': /* non-contiguous memory */
199 amiga_flags |=
200 (get_number(&path) & 3) << 1;
201 break;
202 case 'p': /* Select fastmem by priority */
203 p_flag++;
204 break;
205 case 'q':
206 boothowto |= AB_QUIET;
207 break;
208 case 's': /* single-user state */
209 boothowto |= RB_SINGLE;
210 break;
211 case 't': /* test flag */
212 t_flag = 1;
213 break;
214 case 'v':
215 boothowto |= AB_VERBOSE;
216 break;
217 case 'A': /* enable AGA modes */
218 amiga_flags |= 1;
219 break;
220 case 'D': /* enter Debugger */
221 boothowto |= RB_KDB;
222 break;
223 case 'I': /* inhibit sync negotiation */
224 I_flag = get_number(&path);
225 break;
226 case 'K': /* remove 1st 4MB fastmem */
227 break;
228 case 'S': /* include debug symbols */
229 S_flag = 1;
230 break;
231 }
232 }
233 } else {
234 /* XXX Handle kernel_name differently */
235 kernel_name = path;
236 while ((c = *++path) && c != ' ')
237 ;
238 if (c)
239 *path++ = 0;
240 }
241 }
242 /* XXX Handle kernel_name differently */
243 while ((c = *kernel_name) && c == ' ')
244 ++kernel_name;
245 path = kernel_name;
246 while ((c = *path) && c != ' ')
247 ++path;
248 if (c)
249 *path = 0;
250
251 if (get_cpuid(&cpuid))
252 goto out;
253
254 ExpansionBase = OpenLibrary("expansion.library", 0);
255 if (!ExpansionBase) {
256 printf("can't open %s\n", "expansion.library");
257 return 1;
258 }
259
260 for (ncd=0, cd=0; (cd = FindConfigDev(cd, -1, -1)); ncd++)
261 /* nothing */;
262
263 /* find memory list */
264
265 memseg = (struct boot_memseg *)alloc(16*sizeof(struct boot_memseg));
266
267 /* Forbid(); */
268
269 nseg = 0;
270 mh = SysBase->MemLst;
271 vfrom = mh->Lower & -__PGSZ;
272 vsize = (mh->Upper & -__PGSZ) - vfrom;
273 contflag = mapped1to1 = 0;
274
275 do {
276 size = vsize;
277
278 if (SysBase->LibNode.Version > 36) {
279 from = CachePreDMA(vfrom, &size, contflag);
280 contflag = DMAF_Continue;
281 mapped1to1 = (from == vfrom);
282 vsize -= size;
283 vfrom += size;
284 } else {
285 from = vfrom;
286 mapped1to1 = 1;
287 vsize = 0;
288 }
289
290 #ifdef DEBUG_MEMORY_LIST
291 printf("%lx %lx %lx %ld/%lx %lx\n",
292 (long)from, (long)size,
293 (long)mh->Attribs, (long)mh->Pri,
294 (long)vfrom, (long)vsize);
295 #endif
296 /* Insert The Evergrowing Kludge List Here: */
297
298 /* a) dont load kernel over DraCo MMU table */
299
300 if (((cpuid >> 24) == 0x7D) &&
301 ((from & -DRACOMMUMARGIN) == 0x40000000) &&
302 (size >= DRACOMMUMARGIN)) {
303
304 memseg[nseg].ms_start = from & -DRACOMMUMARGIN;
305 memseg[nseg].ms_size = DRACOMMUMARGIN;
306 memseg[nseg].ms_attrib = mh->Attribs;
307 memseg[nseg].ms_pri = mh->Pri;
308
309 size -= DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1));
310 from += DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1));
311 ++nseg;
312 }
313
314 if ((mh->Attribs & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) {
315 size += from;
316 cmemsz = size;
317 from = 0;
318 } else if ((fmemsz < size) && mapped1to1) {
319 fmem = from;
320 fmemsz = size;
321 }
322
323 memseg[nseg].ms_start = from;
324 memseg[nseg].ms_size = size;
325 memseg[nseg].ms_attrib = mh->Attribs;
326 memseg[nseg].ms_pri = mh->Pri;
327
328 if (vsize == 0) {
329 mh = mh->next;
330 contflag = 0;
331 if (mh->next) {
332 vfrom = mh->Lower & -__PGSZ;
333 vsize = (mh->Upper & -__PGSZ) - vfrom;
334 }
335 }
336 } while ((++nseg <= 16) && vsize);
337
338 /* Permit(); */
339
340 if (k_flag) {
341 fmem += 4*1024*1024;
342 fmemsz -= 4*1024*1024;
343 }
344 if (m_value && m_value < fmemsz)
345 fmemsz = m_value;
346
347 /* XXX Loop through list of kernels */
348 printf("Loading %s: ", kernel_name);
349 /*
350 * XXX Call loadfile with COUNT* options to get size
351 * XXX Allocate memory for kernel + additional data
352 * XXX Call loadfile with LOAD* options to load text/data/symbols
353 */
354 marks[MARK_START] = 0;
355 if (loadfile(kernel_name, marks,
356 COUNT_TEXT|COUNT_TEXTA|COUNT_DATA|COUNT_BSS |
357 (S_flag ? (COUNT_SYM|COUNT_HDR) : 0)) == -1) {
358 goto err;
359 }
360 ksize = ((marks[MARK_END] + 3) & ~3)
361 + sizeof(*nkcd) + ncd*sizeof(*cd)
362 + sizeof(*nkcd) + nseg * sizeof(struct boot_memseg);
363
364 #ifdef PPCBOOTER
365 kp = alloc(ksize);
366 #else
367 kp = alloc(ksize + 256 + ((u_char *)startit_end - (u_char *)startit));
368 #endif
369 if (kp == 0) {
370 errno = ENOMEM;
371 goto err;
372 }
373
374 marks[MARK_START] = (u_long)kp;
375 if (loadfile(kernel_name, marks,
376 LOAD_TEXT|LOAD_TEXTA|LOAD_DATA|LOAD_BSS|
377 (S_flag ? (LOAD_SYM|LOAD_HDR) : 0)) == -1) {
378 printf("Kernel load failed\n");
379 goto err;
380 }
381 marks[MARK_END] = (marks[MARK_END] + 3) & ~3;
382 nkcd = (int *)marks[MARK_END];
383 if (S_flag)
384 esym = (void*)(marks[MARK_END] - marks[MARK_START]);
385 /* #ifndef PPCBOOTER*/
386 kvers = (u_short *)(marks[MARK_ENTRY] - 2);
387
388 if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73) {
389 printf("\nnewer bootblock required: %ld\n", (long)*kvers);
390 goto freeall;
391 }
392 if (*kvers < KERNEL_STARTUP_VERSION || *kvers == 0x4e73) {
393 printf("\nkernel too old for bootblock\n");
394 goto freeall;
395 }
396 #if 0
397 if (*kvers > KERNEL_STARTUP_VERSION)
398 printf("\nKernel V%ld newer than bootblock V%ld\n",
399 (long)*kvers, (long)KERNEL_STARTUP_VERSION);
400 #endif
401 if (marks[MARK_NSYM] && (*kvers == 0x4e73 || *kvers <= 1)) {
402 nkcd = (int *)marks[MARK_SYM];
403 esym = 0;
404 printf("Supressing %ld kernel symbols\n", marks[MARK_NSYM]);
405 timelimit = 60;
406 (void)getchar();
407 }
408 /* version checks */
409 putchar('\n');
410
411 *nkcd = ncd;
412 kcd = (struct cfdev *)(nkcd + 1);
413
414 while ((cd = FindConfigDev(cd, -1, -1))) {
415 *kcd = *cd;
416 #ifndef PPCBOOTER
417 if (((cpuid >> 24) == 0x7D) &&
418 ((u_long)kcd->addr < 0x1000000)) {
419 kcd->addr = (char *)kcd->addr + 0x3000000;
420 }
421 #endif
422 ++kcd;
423 }
424
425 nkcd = (int32_t *)kcd;
426 *nkcd = nseg;
427
428 kmemseg = (struct boot_memseg *)(nkcd + 1);
429
430 while (nseg-- > 0)
431 *kmemseg++ = *memseg++;
432
433 #ifdef PPCBOOTER
434 /*
435 * we use the ppc starter...
436 */
437 start_it = startit;
438 #else
439 /*
440 * Copy startup code to end of kernel image and set start_it.
441 */
442 memcpy((char *)kp + ksize + 256, (char *)startit,
443 (char *)startit_end - (char *)startit);
444 CacheClearU();
445 start_it = (void *)((char *)kp + ksize + 256);
446 #endif
447 printf("*** Loading from %08lx to Fastmem %08lx ***\n",
448 (u_long)kp, (u_long)fmem);
449 /* sleep(2); */
450
451 #if 0
452 printf("would start(kp=0x%lx, ksize=%ld, entry=0x%lx,\n"
453 "fmem=0x%lx, fmemsz=%ld, cmemsz=%ld\n"
454 "boothow=0x%lx, esym=0x%lx, cpuid=0x%lx, eclock=%ld\n"
455 "amigaflags=0x%lx, I_flags=0x%lx, ok?\n",
456 (u_long)kp, (u_long)ksize, marks[MARK_ENTRY] - marks[MARK_START],
457 (u_long)fmem, (u_long)fmemsz, (u_long)cmemsz,
458 (u_long)boothowto, (u_long)esym, (u_long)cpuid, (u_long)eclock,
459 (u_long)amiga_flags, (u_long)I_flag);
460 timelimit = 60;
461 (void)getchar();
462 #endif
463 #ifdef DEBUG_MEMORY_LIST
464 timelimit = 0;
465 #else
466 timelimit = 2;
467 #endif
468 (void)getchar();
469
470 #ifdef PPCBOOTER
471 startit
472 #else
473 start_it
474 #endif
475 (kp, ksize, marks[MARK_ENTRY] - marks[MARK_START], (void *)fmem, fmemsz, cmemsz,
476 boothowto, esym, cpuid, eclock, amiga_flags, I_flag,
477 aio_base >> 9, 1);
478 /*NOTREACHED*/
479
480 freeall:
481 dealloc(kp, ksize);
482 err:
483 printf("\nError %ld\n", (long)errno);
484 goto again;
485 out:
486 timelimit = 10;
487 (void)getchar();
488 return 1;
489 }
490
491 static
492 long get_number(char **ptr)
493 {
494 long value = 0;
495 int base = 10;
496 char *p = *ptr;
497 char c;
498 char sign = 0;
499
500 c = *++p;
501 while (c == ' ')
502 c = *++p;
503 if (c == '-') {
504 sign = -1;
505 c = *++p;
506 }
507 if (c == '$') {
508 base = 16;
509 c = *++p;
510 } else if (c == '0') {
511 c = *++p;
512 if ((c & 0xdf) == 'X') {
513 base = 16;
514 c = *++p;
515 }
516 }
517 while (c) {
518 if (c >= '0' && c <= '9')
519 c -= '0';
520 else {
521 c = (c & 0xdf) - 'A' + 10;
522 if (base != 16 || c < 10 || c > 15)
523 break;
524 }
525 value = value * base + c;
526 c = *++p;
527 }
528 *ptr = p - 1;
529 #ifdef TEST
530 fprintf(stderr, "get_number: got %c0x%x",
531 sign ? '-' : '+', value);
532 #endif
533 return (sign ? -value : value);
534 }
535
536 /*
537 * Try to determine the machine ID by searching the resident module list
538 * for modules only present on specific machines. (Thanks, Bill!)
539 */
540
541 int
542 get_cpuid(u_int32_t *cpuid)
543 {
544 uint8_t alicerev;
545
546 alicerev = *((uint8_t *)0xdff004) & 0x6f;
547 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */
548
549 if (*cpuid & 0xffff0000) {
550 if ((*cpuid >> 24) == 0x7D)
551 return 0;
552
553 switch (*cpuid >> 16) {
554 case 500:
555 case 600:
556 case 1000:
557 case 1200:
558 case 2000:
559 case 3000:
560 case 4000:
561 return 0;
562 default:
563 printf("Amiga %ld ???\n",
564 (long)(*cpuid >> 16));
565 return(1);
566 }
567 }
568 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
569 || FindResident("A1000 Bonus"))
570 *cpuid |= 4000 << 16;
571 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus")
572 || (SysBase->LibNode.Version == 36))
573 *cpuid |= 3000 << 16;
574 else if (OpenResource("card.resource")) {
575 if (alicerev == 0x22 || alicerev == 0x23)
576 *cpuid |= 1200 << 16; /* AGA + PCMCIA = A1200 */
577 else
578 *cpuid |= 600 << 16; /* noAGA + PCMCIA = A600 */
579 } else if (OpenResource("draco.resource")) {
580 *cpuid |= (32000 | DRACOREVISION) << 16;
581 }
582 /*
583 * Nothing found, it's probably an A2000 or A500
584 */
585 if ((*cpuid >> 16) == 0)
586 *cpuid |= 2000 << 16;
587
588 return 0;
589 }
590