main.c revision 1.25 1 /*
2 * $NetBSD: main.c,v 1.25 2009/11/15 20:38:35 snj 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 extern const char bootprog_date[];
64 extern const char bootprog_maker[];
65
66 void startit(void *, u_long, u_long, void *, u_long, u_long, int, void *,
67 int, int, u_long, u_long, u_long, int);
68 int get_cpuid(u_int32_t *);
69 #ifdef PPCBOOTER
70 u_int16_t kickstart[];
71 size_t kicksize;
72 #else
73 void startit_end(void);
74 #endif
75
76 /*
77 * Kernel startup interface version
78 * 1: first version of loadbsd
79 * 2: needs esym location passed in a4
80 * 3: load kernel image into fastmem rather than chipmem
81 * MAX: highest version with backward compatibility.
82 */
83
84 #define KERNEL_STARTUP_VERSION 3
85 #define KERNEL_STARTUP_VERSION_MAX 9
86
87 static long get_number(char **);
88
89 extern char default_command[];
90
91 int
92 pain(void *aio, void *cons)
93 {
94 char linebuf[128];
95 char *kernel_name = default_command;
96 char *path = default_command;
97 int boothowto = RB_AUTOBOOT;
98 u_int32_t cpuid = 0;
99 int amiga_flags = 0;
100 u_int32_t I_flag = 0;
101 int k_flag = 0;
102 int p_flag = 0;
103 int m_value = 0;
104 int S_flag = 0;
105 int t_flag = 0;
106
107 u_int32_t fmem = 0x0;
108 int fmemsz = 0x0;
109 int cmemsz = 0x0;
110 int eclock = SysBase->EClockFreq;
111 /* int skip_chipmem = 0; */
112
113 void (*start_it)(void *, u_long, u_long, void *, u_long, u_long, int,
114 void *, int, int, u_long, u_long, u_long, int);
115
116 void *kp;
117 u_int16_t *kvers;
118 int ksize;
119 void *esym = 0;
120 int32_t *nkcd;
121 struct cfdev *cd, *kcd;
122 struct boot_memseg *kmemseg;
123 struct boot_memseg *memseg;
124 struct MemHead *mh;
125 u_int32_t from, size, vfrom, vsize;
126 int contflag, mapped1to1;
127
128 int ncd, nseg;
129 char c;
130
131 u_long marks[MARK_MAX];
132
133 extern u_int16_t timelimit;
134
135 extern u_int32_t aio_base;
136
137 xdinit(aio);
138
139 if (consinit(cons))
140 return(1);
141
142 /*
143 * we need V36 for: EClock, RDB Bootblocks, CacheClearU
144 */
145
146 if (SysBase->LibNode.Version < EXECMIN) {
147 printf("Exec V%ld, need V%ld\n",
148 (long)SysBase->LibNode.Version, (long)EXECMIN);
149 goto out;
150 }
151
152 /*
153 * XXX Do this differently; default boot will attempt to load a list of
154 * XXX kernels until one of them succeeds.
155 */
156 timelimit = 3;
157 again:
158 #ifdef PPCBOOTER
159 printf("\nNetBSD/AmigaPPC " NETBSD_VERS " Bootstrap, Revision %s\n",
160 bootprog_rev);
161 #else
162 printf("\nNetBSD/Amiga " NETBSD_VERS " Bootstrap, Revision %s\n",
163 bootprog_rev);
164 #endif
165 printf("(%s, %s)\n", bootprog_maker, bootprog_date);
166 printf("\n");
167 printf("Boot: [%s] ", kernel_name);
168
169 gets(linebuf);
170
171 if (*linebuf == 'q')
172 return 1;
173
174 if (*linebuf)
175 path = linebuf;
176
177 /*
178 * parse boot command for path name and process any options
179 */
180 while ((c = *path)) {
181 while (c == ' ')
182 c = *++path;
183 if (c == '-') {
184 while ((c = *++path) && c != ' ') {
185 switch (c) {
186 case 'a': /* multi-user state */
187 boothowto &= ~RB_SINGLE;
188 break;
189 case 'b': /* ask for root device */
190 boothowto |= RB_ASKNAME;
191 break;
192 case 'c': /* force machine model */
193 cpuid = get_number(&path) << 16;
194 break;
195 case 'k': /* Reserve first 4M fastmem */
196 k_flag++;
197 break;
198 case 'm': /* Force fastmem size */
199 m_value = get_number(&path) * 1024;
200 break;
201 case 'n': /* non-contiguous memory */
202 amiga_flags |=
203 (get_number(&path) & 3) << 1;
204 break;
205 case 'p': /* Select fastmem by priority */
206 p_flag++;
207 break;
208 case 'q':
209 boothowto |= AB_QUIET;
210 break;
211 case 's': /* single-user state */
212 boothowto |= RB_SINGLE;
213 break;
214 case 't': /* test flag */
215 t_flag = 1;
216 break;
217 case 'v':
218 boothowto |= AB_VERBOSE;
219 break;
220 case 'A': /* enable AGA modes */
221 amiga_flags |= 1;
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 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */
548 if (*cpuid & 0xffff0000) {
549 if ((*cpuid >> 24) == 0x7D)
550 return 0;
551
552 switch (*cpuid >> 16) {
553 case 500:
554 case 600:
555 case 1000:
556 case 1200:
557 case 2000:
558 case 3000:
559 case 4000:
560 return 0;
561 default:
562 printf("Amiga %ld ???\n",
563 (long)(*cpuid >> 16));
564 return(1);
565 }
566 }
567 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
568 || FindResident("A1000 Bonus"))
569 *cpuid |= 4000 << 16;
570 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus")
571 || (SysBase->LibNode.Version == 36))
572 *cpuid |= 3000 << 16;
573 else if (OpenResource("card.resource")) {
574 /* Test for AGA? */
575 *cpuid |= 1200 << 16;
576 } else if (OpenResource("draco.resource")) {
577 *cpuid |= (32000 | DRACOREVISION) << 16;
578 }
579 /*
580 * Nothing found, it's probably an A2000 or A500
581 */
582 if ((*cpuid >> 16) == 0)
583 *cpuid |= 2000 << 16;
584
585 return 0;
586 }
587