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