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