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