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