loadbsd.c revision 1.24 1 /* $NetBSD: loadbsd.c,v 1.24 2000/06/15 13:43:35 is Exp $ */
2
3 /*
4 * Copyright (c) 1994 Michael L. Hitch
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Michael L. Hitch.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #include <a.out.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <signal.h>
40 #ifdef __NetBSD__
41 #include <err.h>
42 #endif
43 #include <exec/types.h>
44 #include <exec/execbase.h>
45 #include <exec/memory.h>
46 #include <exec/resident.h>
47 #include <graphics/gfxbase.h>
48 #include <libraries/configregs.h>
49 #include <libraries/configvars.h>
50 #include <libraries/expansion.h>
51 #include <libraries/expansionbase.h>
52
53 #include <inline/exec.h>
54 #include <inline/expansion.h>
55 #include <inline/graphics.h>
56
57 /* Get definitions for boothowto */
58 #include "reboot.h"
59
60 #undef __LDPGSZ
61 #define __LDPGSZ 8192
62
63 #ifndef __NetBSD__
64 #ifndef __P
65 #ifdef __STDC__
66 #define __P(x) x
67 #else
68 #define __P(x)
69 #endif
70 #endif
71 void err __P((int, const char *, ...));
72 void errx __P((int, const char *, ...));
73 void warn __P((const char *, ...));
74 void warnx __P((const char *, ...));
75 #endif
76
77 /*
78 * Version history:
79 * 1.x Kernel startup interface version check.
80 * 2.0 Added symbol table end address and symbol table support.
81 * 2.1 03/23/94 - Round up end of fastram segment.
82 * Check fastram segment size for minimum of 2M.
83 * Use largest segment of highest priority if -p option.
84 * Print out fastram size in KB if not a multiple of MB.
85 * 2.2 03/24/94 - Zero out all unused registers.
86 * Started version history comment.
87 * 2.3 04/26/94 - Added -D option to enter debugger on boot.
88 * 2.4 04/30/94 - Cpuid includes base machine type.
89 * Also check if CPU is capable of running NetBSD.
90 * 2.5 05/17/94 - Add check for "A3000 bonus".
91 * 2.6 06/05/94 - Added -c option to override machine type.
92 * 2.7 06/15/94 - Pass E clock frequency.
93 * 2.8 06/22/94 - Fix supervisor stack usage.
94 * 2.9 06/26/94 - Use PAL flag for E clock freq on pre 2.0 WB
95 * Added AGA enable parameter
96 * 2.10 12/22/94 - Use FindResident() & OpenResource() for machine
97 * type detection.
98 * Add -n flag & option for non-contiguous memory.
99 * 01/28/95 - Corrected -n on usage & help messages.
100 * 2.11 03/12/95 - Check kernel size against chip memory size.
101 * 2.12 11/11/95 - Add -I option to inhibit synchronous transfer
102 * 11/12/95 - New kernel startup interface version - to
103 * support loading kernel image to fastmem rather than chipmem.
104 * 2.13 04/15/96 - Direct load to fastmem.
105 * Add -Z flag to force chipmem load.
106 * Moved test mode exit to later - kernel image is created
107 * and startup interface version checked in test mode.
108 * Add -s flag for compatibility to bootblock loader.
109 * 05/02/96 - Add a maximum startup interface version level
110 * to allow future kernel compatibility.
111 * 2.14 06/26/96 is - Add first version of kludges needed to
112 * boot on DraCos. This can probably be done a bit more cleanly
113 * using TTRs, but it works for now.
114 * 2.15 07/28/96 is - Add first version of kludges needed to
115 * get FusionForty kickrom'd memory back. Hope this doesn't
116 * break anything else.
117 */
118 static const char _version[] = "$VER: LoadBSD 2.15 (28.7.96)";
119
120 /*
121 * Kernel startup interface version
122 * 1: first version of loadbsd
123 * 2: needs esym location passed in a4
124 * 3: load kernel image into fastmem rather than chipmem
125 * MAX: highest version with backward compatibility.
126 */
127 #define KERNEL_STARTUP_VERSION 3
128 #define KERNEL_STARTUP_VERSION_MAX 9
129
130 #define DRACOREVISION (*(UBYTE *)0x02000009)
131 #define DRACOMMUMARGIN 0x200000
132
133 #define MAXMEMSEG 16
134 struct boot_memlist {
135 u_int m_nseg; /* num_mem; */
136 struct boot_memseg {
137 u_int ms_start;
138 u_int ms_size;
139 u_short ms_attrib;
140 short ms_pri;
141 } m_seg[MAXMEMSEG];
142 };
143 struct boot_memlist memlist;
144 struct boot_memlist *kmemlist;
145
146
147 void get_mem_config __P((void **, u_long *, u_long *));
148 void get_cpuid __P((void));
149 void get_eclock __P((void));
150 void get_AGA __P((void));
151 void usage __P((void));
152 void verbose_usage __P((void));
153 void Version __P((void));
154 void startit __P((void *, u_long, u_long, void *, u_long, u_long, int, void *,
155 int, int, u_long, u_long, int));
156 void startit_end __P((void));
157
158 extern struct ExecBase *SysBase;
159 extern char *optarg;
160 extern int optind;
161
162 int k_flag;
163 int p_flag;
164 int t_flag;
165 int reqmemsz;
166 int S_flag;
167 u_long I_flag;
168 int Z_flag;
169 u_long cpuid;
170 long eclock_freq;
171 long amiga_flags;
172 char *program_name;
173 char *kname;
174 struct ExpansionBase *ExpansionBase;
175 struct GfxBase *GfxBase;
176 u_char *kp;
177 int ksize;
178
179 int
180 main(argc, argv)
181 int argc;
182 char **argv;
183 {
184 struct exec e;
185 struct ConfigDev *cd, *kcd;
186 u_long fmemsz, cmemsz;
187 int fd, boothowto, textsz, stringsz, ncd, i, mem_ix, ch;
188 u_short *kvers;
189 int *nkcd;
190 void *fmem;
191 char *esym;
192 void (*start_it) __P((void *, u_long, u_long, void *, u_long, u_long,
193 int, void *, int, int, u_long, u_long, int)) = startit;
194
195 program_name = argv[0];
196 boothowto = RB_SINGLE;
197
198 if (argc < 2)
199 usage();
200 if ((GfxBase = (void *)OpenLibrary(GRAPHICSNAME, 0)) == NULL)
201 err(20, "can't open graphics library");
202 if ((ExpansionBase=(void *)OpenLibrary(EXPANSIONNAME, 0)) == NULL)
203 err(20, "can't open expansion library");
204
205 while ((ch = getopt(argc, argv, "aAbc:DhI:km:n:ptsSVZ")) != -1) {
206 switch (ch) {
207 case 'k':
208 k_flag = 1;
209 break;
210 case 'a':
211 boothowto &= ~(RB_SINGLE);
212 boothowto |= RB_AUTOBOOT;
213 break;
214 case 'b':
215 boothowto |= RB_ASKNAME;
216 break;
217 case 'p':
218 p_flag = 1;
219 break;
220 case 't':
221 t_flag = 1;
222 break;
223 case 'm':
224 reqmemsz = atoi(optarg) * 1024;
225 break;
226 case 's':
227 boothowto &= ~(RB_AUTOBOOT);
228 boothowto |= RB_SINGLE;
229 break;
230 case 'V':
231 fprintf(stderr,"%s\n",_version + 6);
232 break;
233 case 'S':
234 S_flag = 1;
235 break;
236 case 'D':
237 boothowto |= RB_KDB;
238 break;
239 case 'c':
240 cpuid = atoi(optarg) << 16;
241 break;
242 case 'A':
243 amiga_flags |= 1;
244 break;
245 case 'n':
246 i = atoi(optarg);
247 if (i >= 0 && i <= 3)
248 amiga_flags |= i << 1;
249 else
250 err(20, "-n option must be 0, 1, 2, or 3");
251 break;
252 case 'I':
253 I_flag = strtoul(optarg, NULL, 16);
254 break;
255 case 'Z':
256 Z_flag = 1;
257 break;
258 case 'h':
259 verbose_usage();
260 default:
261 usage();
262 }
263 }
264 argc -= optind;
265 argv += optind;
266
267 if (argc != 1)
268 usage();
269 kname = argv[0];
270
271 if ((fd = open(kname, 0)) < 0)
272 err(20, "open");
273 if (read(fd, &e, sizeof(e)) != sizeof(e))
274 err(20, "reading exec");
275 if (e.a_magic != NMAGIC)
276 err(20, "unknown binary");
277
278 for (cd = 0, ncd = 0; cd = FindConfigDev(cd, -1, -1); ncd++)
279 ;
280 get_cpuid();
281 get_mem_config(&fmem, &fmemsz, &cmemsz);
282 get_eclock();
283 get_AGA();
284
285 textsz = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
286 esym = NULL;
287 ksize = textsz + e.a_data + e.a_bss + ncd * sizeof(*cd)
288 + 4 + memlist.m_nseg * sizeof(struct boot_memseg) + 4;
289
290 /*
291 * get symbol table size & string size
292 * (should check kernel version to see if it will handle it)
293 */
294 if (S_flag && e.a_syms) {
295 if (lseek(fd, e.a_text + e.a_data + e.a_syms, SEEK_CUR) <= 0
296 || read(fd, &stringsz, 4) != 4
297 || lseek(fd, sizeof(e), SEEK_SET) < 0)
298 err(20, "lseek for symbols");
299 ksize += e.a_syms + 4 + ((stringsz + 3) & ~3);
300 }
301
302 kp = (u_char *)AllocMem(ksize + ((char *)startit_end - (char *)startit) + 256,
303 MEMF_FAST|MEMF_REVERSE);
304 if (t_flag) {
305 for (i = 0; i < memlist.m_nseg; ++i) {
306 printf("mem segment %d: start=%08lx size=%08lx"
307 " attribute=%04lx pri=%d\n",
308 i + 1, memlist.m_seg[i].ms_start,
309 memlist.m_seg[i].ms_size,
310 memlist.m_seg[i].ms_attrib,
311 memlist.m_seg[i].ms_pri);
312 }
313 printf("kernel size: %d\n", ksize);
314 }
315 if (kp == NULL)
316 err(20, "failed malloc %d\n", ksize);
317
318 if (read(fd, kp, e.a_text) != e.a_text
319 || read(fd, kp + textsz, e.a_data) != e.a_data)
320 err(20, "unable to read kernel image\n");
321
322 if (k_flag) {
323 fmem += 4 * 1024 * 1024;
324 fmemsz -= 4 * 1024 * 1024;
325 }
326
327 if (reqmemsz && reqmemsz <= fmemsz)
328 fmemsz = reqmemsz;
329 if (boothowto & RB_AUTOBOOT)
330 printf("Autobooting...");
331 if (boothowto & RB_ASKNAME)
332 printf("Askboot...");
333
334 printf("Using %d%c FASTMEM at 0x%x, %dM CHIPMEM\n",
335 (fmemsz & 0xfffff) ? fmemsz >> 10 : fmemsz >> 20,
336 (fmemsz & 0xfffff) ? 'K' : 'M', fmem, cmemsz >> 20);
337 kvers = (u_short *)(kp + e.a_entry - 2);
338 if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73)
339 err(20, "newer loadbsd required: %d\n", *kvers);
340 if (*kvers > KERNEL_STARTUP_VERSION) {
341 printf("****************************************************\n");
342 printf("*** Notice: this kernel has features which require\n");
343 printf("*** a newer version of loadbsd. To allow the use of\n");
344 printf("*** any newer features or capabilities, you should\n");
345 printf("*** update to a newer version of loadbsd\n");
346 printf("****************************************************\n");
347 sleep(3); /* even more time to see that message */
348 }
349 if ((cpuid & AFB_68020) == 0)
350 err(20, "cpu not supported");
351 /*
352 * give them a chance to read the information...
353 */
354 sleep(2);
355
356 bzero(kp + textsz + e.a_data, e.a_bss);
357 /*
358 * If symbols wanted (and kernel can handle them),
359 * load symbol table & strings and set esym to end.
360 */
361 nkcd = (int *)(kp + textsz + e.a_data + e.a_bss);
362 if (*kvers != 0x4e73 && *kvers > 1 && S_flag && e.a_syms) {
363 *nkcd++ = e.a_syms;
364 read(fd, (char *)nkcd, e.a_syms);
365 nkcd = (int *)((char *)nkcd + e.a_syms);
366 read(fd, (char *)nkcd, stringsz);
367 nkcd = (int*)((char *)nkcd + ((stringsz + 3) & ~3));
368 esym = (char *)(textsz + e.a_data + e.a_bss
369 + e.a_syms + 4 + ((stringsz + 3) & ~3));
370 }
371 *nkcd = ncd;
372
373 kcd = (struct ConfigDev *)(nkcd + 1);
374 while(cd = FindConfigDev(cd, -1, -1)) {
375 *kcd = *cd;
376 if (((cpuid >> 24) == 0x7d) &&
377 ((u_long)kcd->cd_BoardAddr < 0x1000000)) {
378 if (t_flag)
379 printf("Transformed Z2 device from %08lx ",
380 kcd->cd_BoardAddr);
381 kcd->cd_BoardAddr += 0x3000000;
382
383 if (t_flag)
384 printf("to %08lx\n", kcd->cd_BoardAddr);
385 }
386 ++kcd;
387 }
388
389 kmemlist = (struct boot_memlist *)kcd;
390 kmemlist->m_nseg = memlist.m_nseg;
391 for (mem_ix = 0; mem_ix < memlist.m_nseg; mem_ix++)
392 kmemlist->m_seg[mem_ix] = memlist.m_seg[mem_ix];
393
394 if (*kvers > 2 && Z_flag == 0) {
395 /*
396 * Kernel supports direct load to fastmem, and the -Z
397 * option was not specified. Copy startup code to end
398 * of kernel image and set start_it.
399 */
400 if ((void *)kp < fmem) {
401 printf("Kernel at %08lx, Fastmem used at %08lx\n",
402 kp, fmem);
403 errx(20, "Can't copy upwards yet.\nDefragment your memory and try again OR try the -p OR try the -Z options.");
404 }
405 memcpy(kp + ksize + 256, (char *)startit,
406 (char *)startit_end - (char *)startit);
407 CacheClearU();
408 start_it = (void (*)())kp + ksize + 256;
409 printf("*** Loading from %08lx to Fastmem %08lx ***\n",
410 kp, fmem);
411 sleep(2);
412 } else {
413 /*
414 * Either the kernel doesn't suppport loading directly to
415 * fastmem or the -Z flag was given. Verify kernel image
416 * fits into chipmem.
417 */
418 if (ksize >= cmemsz) {
419 printf("Kernel size %d exceeds Chip Memory of %d\n",
420 ksize, cmemsz);
421 err(20, "Insufficient Chip Memory for kernel");
422 }
423 Z_flag = 1;
424 printf("*** Loading from %08lx to Chipmem ***\n", kp);
425 }
426
427 /*
428 * if test option set, done
429 */
430 if (t_flag) {
431 if (kp)
432 FreeMem(kp, ksize + ((char *)startit_end
433 - (char *)startit) + 256);
434 exit(0);
435 }
436
437 /*
438 * XXX AGA startup - may need more
439 */
440 LoadView(NULL); /* Don't do this if AGA active? */
441 start_it(kp, ksize, e.a_entry, fmem, fmemsz, cmemsz, boothowto, esym,
442 cpuid, eclock_freq, amiga_flags, I_flag, Z_flag == 0);
443 /*NOTREACHED*/
444 }
445
446 void
447 get_mem_config(fmem, fmemsz, cmemsz)
448 void **fmem;
449 u_long *fmemsz, *cmemsz;
450 {
451 struct MemHeader *mh, *nmh;
452 u_int segsz, seg, eseg, nmem, nseg, nsegsz;
453 u_int tseg, tsegsz;
454 char mempri;
455
456 nmem = 0;
457 mempri = -128;
458 *fmemsz = 0;
459 *cmemsz = 0;
460
461 /*
462 * walk thru the exec memory list
463 */
464 Forbid();
465 for (mh = (void *) SysBase->MemList.lh_Head;
466 nmh = (void *) mh->mh_Node.ln_Succ; mh = nmh) {
467
468 nseg = (u_int)mh->mh_Lower;
469 nsegsz = (u_int)mh->mh_Upper - nseg;
470
471 segsz = nsegsz;
472 seg = (u_int)CachePreDMA((APTR)nseg, (LONG *)&segsz, 0L);
473 nsegsz -= segsz, nseg += segsz;
474 for (;segsz;
475 segsz = nsegsz,
476 seg = (u_int)CachePreDMA((APTR)nseg, (LONG *)&segsz, DMA_Continue),
477 nsegsz -= segsz, nseg += segsz, ++nmem) {
478
479 if (t_flag)
480 printf("Translated %08x sz %08x to %08x sz %08x\n",
481 nseg - segsz, nsegsz + segsz, seg, segsz);
482
483 eseg = seg + segsz;
484
485
486 if ((cpuid >> 24) == 0x7D) {
487 /* DraCo MMU table kludge */
488
489 segsz = ((segsz -1) | 0xfffff) + 1;
490 seg = eseg - segsz;
491
492 /*
493 * Only use first SIMM to boot; we know it is VA==PA.
494 * Enter into table and continue. Yes,
495 * this is ugly.
496 */
497 if (seg != 0x40000000) {
498 memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
499 memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
500 memlist.m_seg[nmem].ms_size = segsz;
501 memlist.m_seg[nmem].ms_start = seg;
502 ++nmem;
503 continue;
504 }
505
506 memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
507 memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
508 memlist.m_seg[nmem].ms_size = DRACOMMUMARGIN;
509 memlist.m_seg[nmem].ms_start = seg;
510
511 ++nmem;
512 seg += DRACOMMUMARGIN;
513 segsz -= DRACOMMUMARGIN;
514 }
515
516 memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
517 memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
518 memlist.m_seg[nmem].ms_size = segsz;
519 memlist.m_seg[nmem].ms_start = seg;
520
521 if ((mh->mh_Attributes & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) {
522 /*
523 * there should hardly be more than one entry for
524 * chip mem, but handle it the same nevertheless
525 * cmem always starts at 0, so include vector area
526 */
527 memlist.m_seg[nmem].ms_start = seg = 0;
528 /*
529 * round to multiple of 512K
530 */
531 segsz = (segsz + 512 * 1024 - 1) & -(512 * 1024);
532 memlist.m_seg[nmem].ms_size = segsz;
533 if (segsz > *cmemsz)
534 *cmemsz = segsz;
535 continue;
536 }
537 /*
538 * some heuristics..
539 */
540 seg &= -__LDPGSZ;
541 eseg = (eseg + __LDPGSZ - 1) & -__LDPGSZ;
542
543 /*
544 * get the mem back stolen by incore kickstart on
545 * A3000 with V36 bootrom.
546 */
547 if (eseg == 0x07f80000)
548 eseg = 0x08000000;
549
550 /*
551 * or by zkick on a A2000.
552 */
553 if (seg == 0x280000 &&
554 strcmp(mh->mh_Node.ln_Name, "zkick memory") == 0)
555 seg = 0x200000;
556 /*
557 * or by Fusion Forty fastrom
558 */
559 if ((seg & ~(1024*1024-1)) == 0x11000000) {
560 /*
561 * XXX we should test the name.
562 * Unfortunately, the memory is just called
563 * "32 bit memory" which isn't very specific.
564 */
565 seg = 0x11000000;
566 }
567
568 segsz = eseg - seg;
569 memlist.m_seg[nmem].ms_start = seg;
570 memlist.m_seg[nmem].ms_size = segsz;
571 /*
572 * If this segment is smaller than 2M,
573 * don't use it to load the kernel
574 */
575 if (segsz < 2 * 1024 * 1024)
576 continue;
577 /*
578 * if p_flag is set, select memory by priority
579 * instead of size
580 */
581 if ((!p_flag && segsz > *fmemsz) || (p_flag &&
582 mempri <= mh->mh_Node.ln_Pri && segsz > *fmemsz)) {
583 *fmemsz = segsz;
584 *fmem = (void *)seg;
585 mempri = mh->mh_Node.ln_Pri;
586 }
587
588 }
589 }
590 memlist.m_nseg = nmem;
591 Permit();
592 }
593
594 /*
595 * Try to determine the machine ID by searching the resident module list
596 * for modules only present on specific machines. (Thanks, Bill!)
597 */
598 void
599 get_cpuid()
600 {
601 u_long *rl;
602 struct Resident *rm;
603 struct Node *rn; /* Resource node entry */
604
605 cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */
606 if (cpuid & 0xffff0000) {
607 if ((cpuid >> 24) == 0x7D)
608 return;
609
610 switch (cpuid >> 16) {
611 case 500:
612 case 600:
613 case 1000:
614 case 1200:
615 case 2000:
616 case 3000:
617 case 4000:
618 return;
619 default:
620 printf("machine Amiga %d is not recognized\n",
621 cpuid >> 16);
622 exit(1);
623 }
624 }
625 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
626 || FindResident("A1000 Bonus"))
627 cpuid |= 4000 << 16;
628 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
629 cpuid |= 3000 << 16;
630 else if (OpenResource("card.resource")) {
631 /* Test for AGA? */
632 cpuid |= 1200 << 16;
633 } else if (OpenResource("draco.resource")) {
634 cpuid |= (32000 | DRACOREVISION) << 16;
635 }
636 /*
637 * Nothing found, it's probably an A2000 or A500
638 */
639 if ((cpuid >> 16) == 0)
640 cpuid |= 2000 << 16;
641 }
642
643 void
644 get_eclock()
645 {
646 /* Fix for 1.3 startups? */
647 if (SysBase->LibNode.lib_Version > 36)
648 eclock_freq = SysBase->ex_EClockFrequency;
649 else
650 eclock_freq = (GfxBase->DisplayFlags & PAL) ?
651 709379 : 715909;
652 }
653
654 void
655 get_AGA()
656 {
657 /*
658 * Determine if an AGA mode is active
659 */
660 }
661
662
663 asm("
664 .set ABSEXECBASE,4
665
666 .text
667 .globl _startit
668
669 _startit:
670 movel sp,a3
671 movel 4:w,a6
672 lea pc@(start_super),a5
673 jmp a6@(-0x1e) | supervisor-call
674
675 start_super:
676 movew #0x2700,sr
677
678 | the BSD kernel wants values into the following registers:
679 | a0: fastmem-start
680 | d0: fastmem-size
681 | d1: chipmem-size
682 | d3: Amiga specific flags
683 | d4: E clock frequency
684 | d5: AttnFlags (cpuid)
685 | d7: boothowto
686 | a4: esym location
687 | a2: Inhibit sync flags
688 | All other registers zeroed for possible future requirements.
689
690 lea pc@(_startit),sp | make sure we have a good stack ***
691
692 movel a3@(4),a1 | loaded kernel
693 movel a3@(8),d2 | length of loaded kernel
694 | movel a3@(12),sp | entry point in stack pointer
695 movel a3@(12),a6 | push entry point ***
696 movel a3@(16),a0 | fastmem-start
697 movel a3@(20),d0 | fastmem-size
698 movel a3@(24),d1 | chipmem-size
699 movel a3@(28),d7 | boothowto
700 movel a3@(32),a4 | esym
701 movel a3@(36),d5 | cpuid
702 movel a3@(40),d4 | E clock frequency
703 movel a3@(44),d3 | Amiga flags
704 movel a3@(48),a2 | Inhibit sync flags
705 movel a3@(52),d6 | Load to fastmem flag
706 subl a5,a5 | target, load to 0
707
708 cmpb #0x7D,a3@(36) | is it DraCo?
709 beq nott | yes, switch off MMU later
710
711 | no, it is an Amiga:
712
713 | movew #0xf00,0xdff180 |red
714 | moveb #0,0x200003c8
715 | moveb #63,0x200003c9
716 | moveb #0,0x200003c9
717 | moveb #0,0x200003c9
718
719 movew #(1<<9),0xdff096 | disable DMA on Amigas.
720
721 | ------ mmu off start -----
722
723 btst #3,d5 | AFB_68040,SysBase->AttnFlags
724 beq not040
725
726 | Turn off 68040/060 MMU
727
728 subl a3,a3
729 .word 0x4e7b,0xb003 | movec a3,tc
730 .word 0x4e7b,0xb806 | movec a3,urp
731 .word 0x4e7b,0xb807 | movec a3,srp
732 .word 0x4e7b,0xb004 | movec a3,itt0
733 .word 0x4e7b,0xb005 | movec a3,itt1
734 .word 0x4e7b,0xb006 | movec a3,dtt0
735 .word 0x4e7b,0xb007 | movec a3,dtt1
736 bra nott
737
738 not040:
739 lea pc@(zero),a3
740 pmove a3@,tc | Turn off MMU
741 lea pc@(nullrp),a3
742 pmove a3@,crp | Turn off MMU some more
743 pmove a3@,srp | Really, really, turn off MMU
744
745 | Turn off 68030 TT registers
746
747 btst #2,d5 | AFB_68030,SysBase->AttnFlags
748 beq nott | Skip TT registers if not 68030
749 lea pc@(zero),a3
750 .word 0xf013,0x0800 | pmove a3@,tt0 (gas only knows about 68851 ops..)
751 .word 0xf013,0x0c00 | pmove a3@,tt1 (gas only knows about 68851 ops..)
752
753 nott:
754 | ---- mmu off end ----
755 | movew #0xf60,0xdff180 | orange
756 | moveb #0,0x200003c8
757 | moveb #63,0x200003c9
758 | moveb #24,0x200003c9
759 | moveb #0,0x200003c9
760
761 | ---- copy kernel start ----
762
763 tstl d6 | Can we load to fastmem?
764 beq L0 | No, leave destination at 0
765 movl a0,a5 | Move to start of fastmem chunk
766 addl a0,a6 | relocate kernel entry point
767 L0:
768 movl a1@+,a5@+
769 subl #4,d2
770 bcc L0
771
772 lea pc@(ckend:w),a1
773 movl a5,sp@-
774 movl #_startit_end - ckend,d2
775 L2:
776 movl a1@+,a5@+
777 subl #4,d2
778 bcc L2
779
780 btst #3,d5
781 jeq L1
782 .word 0xf4f8
783 L1: movql #0,d2 | switch off cache to ensure we use
784 movec d2,cacr | valid kernel data
785
786 | movew #0xFF0,0xdff180 | yellow
787 | moveb #0,0x200003c8
788 | moveb #63,0x200003c9
789 | moveb #0,0x200003c9
790 | moveb #0,0x200003c9
791 rts
792
793 | ---- copy kernel end ----
794
795 ckend:
796 | movew #0x0ff,0xdff180 | petrol
797 | moveb #0,0x200003c8
798 | moveb #0,0x200003c9
799 | moveb #63,0x200003c9
800 | moveb #63,0x200003c9
801
802 movl d5,d2
803 roll #8,d2
804 cmpb #0x7D,d2
805 jne noDraCo
806
807 | DraCo: switch off MMU now:
808
809 subl a3,a3
810 .word 0x4e7b,0xb003 | movec a3,tc
811 .word 0x4e7b,0xb806 | movec a3,urp
812 .word 0x4e7b,0xb807 | movec a3,srp
813 .word 0x4e7b,0xb004 | movec a3,itt0
814 .word 0x4e7b,0xb005 | movec a3,itt1
815 .word 0x4e7b,0xb006 | movec a3,dtt0
816 .word 0x4e7b,0xb007 | movec a3,dtt1
817
818 noDraCo:
819 moveq #0,d2 | zero out unused registers
820 moveq #0,d6 | (might make future compatibility
821 movel d6,a1 | would have known contents)
822 movel d6,a3
823 movel d6,a5
824 movel a6,sp | entry point into stack pointer
825 movel d6,a6
826
827 | movew #0x0F0,0xdff180 | green
828 | moveb #0,0x200003c8
829 | moveb #0,0x200003c9
830 | moveb #63,0x200003c9
831 | moveb #0,0x200003c9
832
833 jmp sp@ | jump to kernel entry point
834
835
836 | A do-nothing MMU root pointer (includes the following long as well)
837
838 nullrp: .long 0x7fff0001
839 zero: .long 0
840
841 _startit_end:
842
843 ");
844
845 void
846 usage()
847 {
848 fprintf(stderr, "usage: %s [-abhkpstADSVZ] [-c machine] [-m mem] [-n mode] [-I sync-inhibit] kernel\n",
849 program_name);
850 exit(1);
851 }
852
853
854 void
855 verbose_usage()
856 {
857 fprintf(stderr, "
858 NAME
859 \t%s - loads NetBSD from amiga dos.
860 SYNOPSIS
861 \t%s [-abhkpstADSVZ] [-c machine] [-m mem] [-n flags] [-I sync-inhibit] kernel
862 OPTIONS
863 \t-a Boot up to multiuser mode.
864 \t-A Use AGA display mode, if available.
865 \t-b Ask for which root device.
866 \t Its possible to have multiple roots and choose between them.
867 \t-c Set machine type. [e.g 3000; use 32000+N for DraCo rev. N]
868 \t-D Enter debugger
869 \t-h This help message.
870 \t-I Inhibit sync negotiation. Option value is bit-encoded targets.
871 \t-k Reserve the first 4M of fast mem [Some one else
872 \t is going to have to answer what that it is used for].
873 \t-m Tweak amount of available memory, for finding minimum amount
874 \t of memory required to run. Sets fastmem size to specified
875 \t size in Kbytes.
876 \t-n Enable multiple non-contiguous memory: value = 0 (disabled),
877 \t 1 (two segments), 2 (all avail segments), 3 (same as 2?).
878 \t-p Use highest priority fastmem segement instead of the largest
879 \t segment. The higher priority segment is usually faster
880 \t (i.e. 32 bit memory), but some people have smaller amounts
881 \t of 32 bit memory.
882 \t-s Boot up in singleuser mode (default).
883 \t-S Include kernel symbol table.
884 \t-t This is a *test* option. It prints out the memory
885 \t list information being passed to the kernel and also
886 \t exits without actually starting NetBSD.
887 \t-V Version of loadbsd program.
888 \t-Z Force kernel load to chipmem.
889 HISTORY
890 \tThis version supports Kernel version 720 +\n",
891 program_name, program_name);
892 exit(1);
893 }
894
895
896 void
897 _Vdomessage(doexit, eval, doerrno, fmt, args)
898 int doexit, doerrno, eval;
899 const char *fmt;
900 va_list args;
901 {
902 fprintf(stderr, "%s: ", program_name);
903 if (fmt) {
904 vfprintf(stderr, fmt, args);
905 fprintf(stderr, ": ");
906 }
907 if (doerrno && errno < sys_nerr) {
908 fprintf(stderr, "%s", strerror(errno));
909 #if 0
910 if (errno == EINTR || errno == 0) {
911 int sigs;
912 sigpending((sigset_t *)&sigs);
913 printf("%x\n", sigs);
914 }
915 #endif
916 }
917 fprintf(stderr, "\n");
918 if (doexit) {
919 if (kp)
920 FreeMem(kp, ksize + ((char *)startit_end
921 - (char *)startit) + 256);
922 exit(eval);
923 }
924 }
925
926 void
927 err(int eval, const char *fmt, ...)
928 {
929 va_list ap;
930 va_start(ap, fmt);
931 _Vdomessage(1, eval, 1, fmt, ap);
932 /*NOTREACHED*/
933 }
934
935 void
936 errx(int eval, const char *fmt, ...)
937 {
938 va_list ap;
939 va_start(ap, fmt);
940 _Vdomessage(1, eval, 0, fmt, ap);
941 /*NOTREACHED*/
942 }
943
944 void
945 warn(const char *fmt, ...)
946 {
947 va_list ap;
948 va_start(ap, fmt);
949 _Vdomessage(0, 0, 1, fmt, ap);
950 va_end(ap);
951 }
952
953 void
954 warnx(const char *fmt, ...)
955 {
956 va_list ap;
957 va_start(ap, fmt);
958 _Vdomessage(0, 0, 0, fmt, ap);
959 va_end(ap);
960 }
961
962
963 u_int
964 sleep(u_int n)
965 {
966 (void)TimeDelay(0L, n, 0L);
967 }
968
969
970