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