main.c revision 1.28 1 /*
2 * $NetBSD: main.c,v 1.28 2011/07/10 21:02:38 mhitch 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 'C': /* Serial Console */
221 amiga_flags |= (1 << 3);
222 break;
223 case 'D': /* enter Debugger */
224 boothowto |= RB_KDB;
225 break;
226 case 'I': /* inhibit sync negotiation */
227 I_flag = get_number(&path);
228 break;
229 case 'K': /* remove 1st 4MB fastmem */
230 break;
231 case 'S': /* include debug symbols */
232 S_flag = 1;
233 break;
234 }
235 }
236 } else {
237 /* XXX Handle kernel_name differently */
238 kernel_name = path;
239 while ((c = *++path) && c != ' ')
240 ;
241 if (c)
242 *path++ = 0;
243 }
244 }
245 /* XXX Handle kernel_name differently */
246 while ((c = *kernel_name) && c == ' ')
247 ++kernel_name;
248 path = kernel_name;
249 while ((c = *path) && c != ' ')
250 ++path;
251 if (c)
252 *path = 0;
253
254 if (get_cpuid(&cpuid))
255 goto out;
256
257 ExpansionBase = OpenLibrary("expansion.library", 0);
258 if (!ExpansionBase) {
259 printf("can't open %s\n", "expansion.library");
260 return 1;
261 }
262
263 for (ncd=0, cd=0; (cd = FindConfigDev(cd, -1, -1)); ncd++)
264 /* nothing */;
265
266 /* find memory list */
267
268 memseg = (struct boot_memseg *)alloc(16*sizeof(struct boot_memseg));
269
270 /* Forbid(); */
271
272 nseg = 0;
273 mh = SysBase->MemLst;
274 vfrom = mh->Lower & -__PGSZ;
275 vsize = (mh->Upper & -__PGSZ) - vfrom;
276 contflag = mapped1to1 = 0;
277
278 do {
279 size = vsize;
280
281 if (SysBase->LibNode.Version > 36) {
282 from = CachePreDMA(vfrom, &size, contflag);
283 contflag = DMAF_Continue;
284 mapped1to1 = (from == vfrom);
285 vsize -= size;
286 vfrom += size;
287 } else {
288 from = vfrom;
289 mapped1to1 = 1;
290 vsize = 0;
291 }
292
293 #ifdef DEBUG_MEMORY_LIST
294 printf("%lx %lx %lx %ld/%lx %lx\n",
295 (long)from, (long)size,
296 (long)mh->Attribs, (long)mh->Pri,
297 (long)vfrom, (long)vsize);
298 #endif
299 /* Insert The Evergrowing Kludge List Here: */
300
301 /* a) dont load kernel over DraCo MMU table */
302
303 if (((cpuid >> 24) == 0x7D) &&
304 ((from & -DRACOMMUMARGIN) == 0x40000000) &&
305 (size >= DRACOMMUMARGIN)) {
306
307 memseg[nseg].ms_start = from & -DRACOMMUMARGIN;
308 memseg[nseg].ms_size = DRACOMMUMARGIN;
309 memseg[nseg].ms_attrib = mh->Attribs;
310 memseg[nseg].ms_pri = mh->Pri;
311
312 size -= DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1));
313 from += DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1));
314 ++nseg;
315 }
316
317 if ((mh->Attribs & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) {
318 size += from;
319 cmemsz = size;
320 from = 0;
321 } else if ((fmemsz < size) && mapped1to1) {
322 fmem = from;
323 fmemsz = size;
324 }
325
326 memseg[nseg].ms_start = from;
327 memseg[nseg].ms_size = size;
328 memseg[nseg].ms_attrib = mh->Attribs;
329 memseg[nseg].ms_pri = mh->Pri;
330
331 if (vsize == 0) {
332 mh = mh->next;
333 contflag = 0;
334 if (mh->next) {
335 vfrom = mh->Lower & -__PGSZ;
336 vsize = (mh->Upper & -__PGSZ) - vfrom;
337 }
338 }
339 } while ((++nseg <= 16) && vsize);
340
341 /* Permit(); */
342
343 if (k_flag) {
344 fmem += 4*1024*1024;
345 fmemsz -= 4*1024*1024;
346 }
347 if (m_value && m_value < fmemsz)
348 fmemsz = m_value;
349
350 /* XXX Loop through list of kernels */
351 printf("Loading %s: ", kernel_name);
352 /*
353 * XXX Call loadfile with COUNT* options to get size
354 * XXX Allocate memory for kernel + additional data
355 * XXX Call loadfile with LOAD* options to load text/data/symbols
356 */
357 marks[MARK_START] = 0;
358 if (loadfile(kernel_name, marks,
359 COUNT_TEXT|COUNT_TEXTA|COUNT_DATA|COUNT_BSS |
360 (S_flag ? (COUNT_SYM|COUNT_HDR) : 0)) == -1) {
361 goto err;
362 }
363 ksize = ((marks[MARK_END] + 3) & ~3)
364 + sizeof(*nkcd) + ncd*sizeof(*cd)
365 + sizeof(*nkcd) + nseg * sizeof(struct boot_memseg);
366
367 #ifdef PPCBOOTER
368 kp = alloc(ksize);
369 #else
370 kp = alloc(ksize + 256 + ((u_char *)startit_end - (u_char *)startit));
371 #endif
372 if (kp == 0) {
373 errno = ENOMEM;
374 goto err;
375 }
376
377 marks[MARK_START] = (u_long)kp;
378 if (loadfile(kernel_name, marks,
379 LOAD_TEXT|LOAD_TEXTA|LOAD_DATA|LOAD_BSS|
380 (S_flag ? (LOAD_SYM|LOAD_HDR) : 0)) == -1) {
381 printf("Kernel load failed\n");
382 goto err;
383 }
384 marks[MARK_END] = (marks[MARK_END] + 3) & ~3;
385 nkcd = (int *)marks[MARK_END];
386 if (S_flag)
387 esym = (void*)(marks[MARK_END] - marks[MARK_START]);
388 /* #ifndef PPCBOOTER*/
389 kvers = (u_short *)(marks[MARK_ENTRY] - 2);
390
391 if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73) {
392 printf("\nnewer bootblock required: %ld\n", (long)*kvers);
393 goto freeall;
394 }
395 if (*kvers < KERNEL_STARTUP_VERSION || *kvers == 0x4e73) {
396 printf("\nkernel too old for bootblock\n");
397 goto freeall;
398 }
399 #if 0
400 if (*kvers > KERNEL_STARTUP_VERSION)
401 printf("\nKernel V%ld newer than bootblock V%ld\n",
402 (long)*kvers, (long)KERNEL_STARTUP_VERSION);
403 #endif
404 if (marks[MARK_NSYM] && (*kvers == 0x4e73 || *kvers <= 1)) {
405 nkcd = (int *)marks[MARK_SYM];
406 esym = 0;
407 printf("Supressing %ld kernel symbols\n", marks[MARK_NSYM]);
408 timelimit = 60;
409 (void)getchar();
410 }
411 /* version checks */
412 putchar('\n');
413
414 *nkcd = ncd;
415 kcd = (struct cfdev *)(nkcd + 1);
416
417 while ((cd = FindConfigDev(cd, -1, -1))) {
418 *kcd = *cd;
419 #ifndef PPCBOOTER
420 if (((cpuid >> 24) == 0x7D) &&
421 ((u_long)kcd->addr < 0x1000000)) {
422 kcd->addr = (char *)kcd->addr + 0x3000000;
423 }
424 #endif
425 ++kcd;
426 }
427
428 nkcd = (int32_t *)kcd;
429 *nkcd = nseg;
430
431 kmemseg = (struct boot_memseg *)(nkcd + 1);
432
433 while (nseg-- > 0)
434 *kmemseg++ = *memseg++;
435
436 #ifdef PPCBOOTER
437 /*
438 * we use the ppc starter...
439 */
440 start_it = startit;
441 #else
442 /*
443 * Copy startup code to end of kernel image and set start_it.
444 */
445 memcpy((char *)kp + ksize + 256, (char *)startit,
446 (char *)startit_end - (char *)startit);
447 CacheClearU();
448 start_it = (void *)((char *)kp + ksize + 256);
449 #endif
450 printf("*** Loading from %08lx to Fastmem %08lx ***\n",
451 (u_long)kp, (u_long)fmem);
452 /* sleep(2); */
453
454 #if 0
455 printf("would start(kp=0x%lx, ksize=%ld, entry=0x%lx,\n"
456 "fmem=0x%lx, fmemsz=%ld, cmemsz=%ld\n"
457 "boothow=0x%lx, esym=0x%lx, cpuid=0x%lx, eclock=%ld\n"
458 "amigaflags=0x%lx, I_flags=0x%lx, ok?\n",
459 (u_long)kp, (u_long)ksize, marks[MARK_ENTRY] - marks[MARK_START],
460 (u_long)fmem, (u_long)fmemsz, (u_long)cmemsz,
461 (u_long)boothowto, (u_long)esym, (u_long)cpuid, (u_long)eclock,
462 (u_long)amiga_flags, (u_long)I_flag);
463 timelimit = 60;
464 (void)getchar();
465 #endif
466 #ifdef DEBUG_MEMORY_LIST
467 timelimit = 0;
468 #else
469 timelimit = 2;
470 #endif
471 (void)getchar();
472
473 #ifdef PPCBOOTER
474 startit
475 #else
476 start_it
477 #endif
478 (kp, ksize, marks[MARK_ENTRY] - marks[MARK_START], (void *)fmem, fmemsz, cmemsz,
479 boothowto, esym, cpuid, eclock, amiga_flags, I_flag,
480 aio_base >> 9, 1);
481 /*NOTREACHED*/
482
483 freeall:
484 dealloc(kp, ksize);
485 err:
486 printf("\nError %ld\n", (long)errno);
487 goto again;
488 out:
489 timelimit = 10;
490 (void)getchar();
491 return 1;
492 }
493
494 static
495 long get_number(char **ptr)
496 {
497 long value = 0;
498 int base = 10;
499 char *p = *ptr;
500 char c;
501 char sign = 0;
502
503 c = *++p;
504 while (c == ' ')
505 c = *++p;
506 if (c == '-') {
507 sign = -1;
508 c = *++p;
509 }
510 if (c == '$') {
511 base = 16;
512 c = *++p;
513 } else if (c == '0') {
514 c = *++p;
515 if ((c & 0xdf) == 'X') {
516 base = 16;
517 c = *++p;
518 }
519 }
520 while (c) {
521 if (c >= '0' && c <= '9')
522 c -= '0';
523 else {
524 c = (c & 0xdf) - 'A' + 10;
525 if (base != 16 || c < 10 || c > 15)
526 break;
527 }
528 value = value * base + c;
529 c = *++p;
530 }
531 *ptr = p - 1;
532 #ifdef TEST
533 fprintf(stderr, "get_number: got %c0x%x",
534 sign ? '-' : '+', value);
535 #endif
536 return (sign ? -value : value);
537 }
538
539 /*
540 * Try to determine the machine ID by searching the resident module list
541 * for modules only present on specific machines. (Thanks, Bill!)
542 */
543
544 int
545 get_cpuid(u_int32_t *cpuid)
546 {
547 uint8_t alicerev;
548
549 alicerev = *((uint8_t *)0xdff004) & 0x6f;
550 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */
551
552 if (*cpuid & 0xffff0000) {
553 if ((*cpuid >> 24) == 0x7D)
554 return 0;
555
556 switch (*cpuid >> 16) {
557 case 500:
558 case 600:
559 case 1000:
560 case 1200:
561 case 2000:
562 case 3000:
563 case 4000:
564 return 0;
565 default:
566 printf("Amiga %ld ???\n",
567 (long)(*cpuid >> 16));
568 return(1);
569 }
570 }
571 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
572 || FindResident("A1000 Bonus"))
573 *cpuid |= 4000 << 16;
574 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus")
575 || (SysBase->LibNode.Version == 36))
576 *cpuid |= 3000 << 16;
577 else if (OpenResource("card.resource")) {
578 if (alicerev == 0x22 || alicerev == 0x23)
579 *cpuid |= 1200 << 16; /* AGA + PCMCIA = A1200 */
580 else
581 *cpuid |= 600 << 16; /* noAGA + PCMCIA = A600 */
582 } else if (OpenResource("draco.resource")) {
583 *cpuid |= (32000 | DRACOREVISION) << 16;
584 }
585 /*
586 * Nothing found, it's probably an A2000 or A500
587 */
588 if ((*cpuid >> 16) == 0)
589 *cpuid |= 2000 << 16;
590
591 return 0;
592 }
593