Home | History | Annotate | Line # | Download | only in loadbsd
loadbsd.c revision 1.17
      1 /*	$NetBSD: loadbsd.c,v 1.17 1995/11/30 00:57:29 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 parameter passing 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 parameter version - to support passing
    103  *		a kernel parameter data structure and support moving kernel
    104  *		image to fastmem rather than chipmem.
    105  */
    106 static const char _version[] = "$VER: LoadBSD 2.12 (12.11.95)";
    107 
    108 /*
    109  * Kernel parameter passing version
    110  *	1:	first version of loadbsd
    111  *	2:	needs esym location passed in a4
    112  *	3:	allow kernel image in fastmem rather than chipmem, and
    113  *		passing kernel parameters in a data structure
    114  */
    115 #define KERNEL_PARAMETER_VERSION	3
    116 
    117 #define MAXMEMSEG	16
    118 struct boot_memlist {
    119 	u_int	m_nseg; /* num_mem; */
    120 	struct boot_memseg {
    121 		u_int	ms_start;
    122 		u_int	ms_size;
    123 		u_short	ms_attrib;
    124 		short	ms_pri;
    125 	} m_seg[MAXMEMSEG];
    126 };
    127 struct boot_memlist memlist;
    128 struct boot_memlist *kmemlist;
    129 
    130 
    131 void get_mem_config __P((void **, u_long *, u_long *));
    132 void get_cpuid __P((void));
    133 void get_eclock __P((void));
    134 void get_AGA __P((void));
    135 void usage __P((void));
    136 void verbose_usage __P((void));
    137 void Version __P((void));
    138 
    139 extern struct ExecBase *SysBase;
    140 extern char *optarg;
    141 extern int optind;
    142 
    143 int k_flag;
    144 int p_flag;
    145 int t_flag;
    146 int reqmemsz;
    147 int S_flag;
    148 u_long I_flag;
    149 u_long cpuid;
    150 long eclock_freq;
    151 long amiga_flags;
    152 char *program_name;
    153 char *kname;
    154 struct ExpansionBase *ExpansionBase;
    155 struct GfxBase *GfxBase;
    156 
    157 
    158 int
    159 main(argc, argv)
    160 	int argc;
    161 	char **argv;
    162 {
    163 	struct exec e;
    164 	struct ConfigDev *cd, *kcd;
    165 	u_long fmemsz, cmemsz;
    166 	int fd, boothowto, ksize, textsz, stringsz, ncd, i, mem_ix, ch;
    167 	u_short *kvers;
    168 	int *nkcd;
    169 	u_char *kp;
    170 	void *fmem;
    171 	char *esym;
    172 
    173 	program_name = argv[0];
    174 	boothowto = RB_SINGLE;
    175 
    176 	if (argc < 2)
    177 		usage();
    178 	if ((GfxBase = (void *)OpenLibrary(GRAPHICSNAME, 0)) == NULL)
    179 		err(20, "can't open graphics library");
    180 	if ((ExpansionBase=(void *)OpenLibrary(EXPANSIONNAME, 0)) == NULL)
    181 		err(20, "can't open expansion library");
    182 
    183 	while ((ch = getopt(argc, argv, "aAbc:DhI:km:n:ptSV")) != EOF) {
    184 		switch (ch) {
    185 		case 'k':
    186 			k_flag = 1;
    187 			break;
    188 		case 'a':
    189 			boothowto &= ~(RB_SINGLE);
    190 			boothowto |= RB_AUTOBOOT;
    191 			break;
    192 		case 'b':
    193 			boothowto |= RB_ASKNAME;
    194 			break;
    195 		case 'p':
    196 			p_flag = 1;
    197 			break;
    198 		case 't':
    199 			t_flag = 1;
    200 			break;
    201 		case 'm':
    202 			reqmemsz = atoi(optarg) * 1024;
    203 			break;
    204 		case 'V':
    205 			fprintf(stderr,"%s\n",_version + 6);
    206 			break;
    207 		case 'S':
    208 			S_flag = 1;
    209 			break;
    210 		case 'D':
    211 			boothowto |= RB_KDB;
    212 			break;
    213 		case 'c':
    214 			cpuid = atoi(optarg) << 16;
    215 			break;
    216 		case 'A':
    217 			amiga_flags |= 1;
    218 			break;
    219 		case 'n':
    220 			i = atoi(optarg);
    221 			if (i >= 0 && i <= 3)
    222 				amiga_flags |= i << 1;
    223 			else
    224 				err(20, "-n option must be 0, 1, 2, or 3");
    225 			break;
    226 		case 'I':
    227 			I_flag = strtoul(optarg, NULL, 16);
    228 			break;
    229 		case 'h':
    230 			verbose_usage();
    231 		default:
    232 			usage();
    233 		}
    234 	}
    235 	argc -= optind;
    236 	argv += optind;
    237 
    238 	if (argc != 1)
    239 		usage();
    240 	kname = argv[0];
    241 
    242 	if ((fd = open(kname, 0)) < 0)
    243 		err(20, "open");
    244 	if (read(fd, &e, sizeof(e)) != sizeof(e))
    245 		err(20, "reading exec");
    246 	if (e.a_magic != NMAGIC)
    247 		err(20, "unknown binary");
    248 
    249 	for (cd = 0, ncd = 0; cd = FindConfigDev(cd, -1, -1); ncd++)
    250 		;
    251 	get_mem_config(&fmem, &fmemsz, &cmemsz);
    252 	get_cpuid();
    253 	get_eclock();
    254 	get_AGA();
    255 
    256 	textsz = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
    257 	esym = NULL;
    258 	ksize = textsz + e.a_data + e.a_bss + ncd * sizeof(*cd)
    259 	    + 4 + memlist.m_nseg * sizeof(struct boot_memseg) + 4;
    260 
    261 	/*
    262 	 * get symbol table size & string size
    263 	 * (should check kernel version to see if it will handle it)
    264 	 */
    265 	if (S_flag && e.a_syms) {
    266 		if (lseek(fd, e.a_text + e.a_data + e.a_syms, SEEK_CUR) <= 0
    267 		    || read(fd, &stringsz, 4) != 4
    268 		    || lseek(fd, sizeof(e), SEEK_SET) < 0)
    269 			err(20, "lseek for symbols");
    270 		ksize += e.a_syms + 4 + stringsz;
    271 	}
    272 
    273 	if (ksize >= cmemsz) {
    274 		printf("Kernel size %d exceeds Chip Memory of %d\n",
    275 		    ksize, cmemsz);
    276 		err(20, "Insufficient Chip Memory for kernel");
    277 	}
    278 	kp = (u_char *)malloc(ksize);
    279 	if (t_flag) {
    280 		for (i = 0; i < memlist.m_nseg; ++i) {
    281 			printf("mem segment %d: start=%08lx size=%08lx"
    282 			    " attribute=%04lx pri=%d\n",
    283 			    i + 1, memlist.m_seg[i].ms_start,
    284 			    memlist.m_seg[i].ms_size,
    285 			    memlist.m_seg[i].ms_attrib,
    286 			    memlist.m_seg[i].ms_pri);
    287 		}
    288 		printf("kernel size: %d\n", ksize);
    289 	}
    290 	if (kp == NULL)
    291 		err(20, "failed malloc %d\n", ksize);
    292 
    293 	if (read(fd, kp, e.a_text) != e.a_text
    294 	    || read(fd, kp + textsz, e.a_data) != e.a_data)
    295 		err(20, "unable to read kernel image\n");
    296 
    297 	if (k_flag) {
    298 		fmem += 4 * 1024 * 1024;
    299 		fmemsz -= 4 * 1024 * 1024;
    300 	}
    301 
    302 	if (reqmemsz && reqmemsz <= fmemsz)
    303 		fmemsz = reqmemsz;
    304 	if (boothowto & RB_AUTOBOOT)
    305 		printf("Autobooting...");
    306 	if (boothowto & RB_ASKNAME)
    307 		printf("Askboot...");
    308 
    309 	printf("Using %d%c FASTMEM at 0x%x, %dM CHIPMEM\n",
    310 	    (fmemsz & 0xfffff) ? fmemsz >> 10 : fmemsz >> 20,
    311 	    (fmemsz & 0xfffff) ? 'K' : 'M', fmem, cmemsz >> 20);
    312 	kvers = (u_short *)(kp + e.a_entry - 2);
    313 	if (*kvers > KERNEL_PARAMETER_VERSION && *kvers != 0x4e73)
    314 		err(20, "newer loadbsd required: %d\n", *kvers);
    315 	if (*kvers > 2) {
    316 		printf("****************************************************\n");
    317 		printf("*** Notice:  this kernel has features which require\n");
    318 		printf("*** a newer version of loadbsd.  To allow the use of\n");
    319 		printf("*** any newer features or capabilities, you should\n");
    320 		printf("*** update your copy of loadbsd\n");
    321 		printf("****************************************************\n");
    322 		sleep(3);	/* even more time to see that message */
    323 	}
    324 	if ((cpuid & AFB_68020) == 0)
    325 		err(20, "cpu not supported");
    326 	/*
    327 	 * give them a chance to read the information...
    328 	 */
    329 	sleep(2);
    330 
    331 	bzero(kp + textsz + e.a_data, e.a_bss);
    332 	/*
    333 	 * If symbols wanted (and kernel can handle them),
    334 	 * load symbol table & strings and set esym to end.
    335 	 */
    336 	nkcd = (int *)(kp + textsz + e.a_data + e.a_bss);
    337 	if (*kvers != 0x4e73 && *kvers > 1 && S_flag && e.a_syms) {
    338 		*nkcd++ = e.a_syms;
    339 		read(fd, (char *)nkcd, e.a_syms);
    340 		nkcd = (int *)((char *)nkcd + e.a_syms);
    341 		read(fd, (char *)nkcd, stringsz);
    342 		    nkcd = (int*)((char *)nkcd + stringsz);
    343 		    esym = (char *)(textsz + e.a_data + e.a_bss
    344 		    + e.a_syms + 4 + stringsz);
    345 	}
    346 	*nkcd = ncd;
    347 
    348 	kcd = (struct ConfigDev *)(nkcd + 1);
    349 	while(cd = FindConfigDev(cd, -1, -1))
    350 		*kcd++ = *cd;
    351 
    352 	kmemlist = (struct boot_memlist *)kcd;
    353 	kmemlist->m_nseg = memlist.m_nseg;
    354 	for (mem_ix = 0; mem_ix < memlist.m_nseg; mem_ix++)
    355 		kmemlist->m_seg[mem_ix] = memlist.m_seg[mem_ix];
    356 	/*
    357 	 * if test option set, done
    358 	 */
    359 	if (t_flag)
    360 		exit(0);
    361 
    362 	/*
    363 	 * XXX AGA startup - may need more
    364 	 */
    365 	LoadView(NULL);		/* Don't do this if AGA active? */
    366 	startit(kp, ksize, e.a_entry, fmem, fmemsz, cmemsz, boothowto, esym,
    367 	    cpuid, eclock_freq, amiga_flags, I_flag);
    368 	/*NOTREACHED*/
    369 }
    370 
    371 void
    372 get_mem_config(fmem, fmemsz, cmemsz)
    373 	void **fmem;
    374 	u_long *fmemsz, *cmemsz;
    375 {
    376 	struct MemHeader *mh, *nmh;
    377 	u_int segsz, seg, eseg, nmem;
    378 	char mempri;
    379 
    380 	nmem = 0;
    381 	mempri = -128;
    382 	*fmemsz = 0;
    383 	*cmemsz = 0;
    384 
    385 	/*
    386 	 * walk thru the exec memory list
    387 	 */
    388 	Forbid();
    389 	for (mh  = (void *) SysBase->MemList.lh_Head;
    390 	    nmh = (void *) mh->mh_Node.ln_Succ; mh = nmh, nmem++) {
    391 		memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
    392 		memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
    393 		seg = (u_int)mh->mh_Lower;
    394 		eseg = (u_int)mh->mh_Upper;
    395 		segsz = eseg - seg;
    396 		memlist.m_seg[nmem].ms_size = segsz;
    397 		memlist.m_seg[nmem].ms_start = seg;
    398 
    399 		if (mh->mh_Attributes & MEMF_CHIP) {
    400 			/*
    401 			 * there should hardly be more than one entry for
    402 			 * chip mem, but handle it the same nevertheless
    403 			 * cmem always starts at 0, so include vector area
    404 			 */
    405 			memlist.m_seg[nmem].ms_start = seg = 0;
    406 			/*
    407 			 * round to multiple of 512K
    408 			 */
    409 			segsz = (segsz + 512 * 1024 - 1) & -(512 * 1024);
    410 			memlist.m_seg[nmem].ms_size = segsz;
    411 			if (segsz > *cmemsz)
    412 				*cmemsz = segsz;
    413 			continue;
    414 		}
    415 		/*
    416 		 * some heuristics..
    417 		 */
    418 		seg &= -__LDPGSZ;
    419 		eseg = (eseg + __LDPGSZ - 1) & -__LDPGSZ;
    420 
    421 		/*
    422 		 * get the mem back stolen by incore kickstart on
    423 		 * A3000 with V36 bootrom.
    424 		 */
    425 		if (eseg == 0x07f80000)
    426 			eseg = 0x08000000;
    427 
    428 		/*
    429 		 * or by zkick on a A2000.
    430 		 */
    431 		if (seg == 0x280000 &&
    432 		    strcmp(mh->mh_Node.ln_Name, "zkick memory") == 0)
    433 			seg = 0x200000;
    434 
    435 		segsz = eseg - seg;
    436 		memlist.m_seg[nmem].ms_start = seg;
    437 		memlist.m_seg[nmem].ms_size = segsz;
    438 		/*
    439 		 *  If this segment is smaller than 2M,
    440 		 *  don't use it to load the kernel
    441 		 */
    442 		if (segsz < 2 * 1024 * 1024)
    443 			continue;
    444 		/*
    445 		 * if p_flag is set, select memory by priority
    446 		 * instead of size
    447 		 */
    448 		if ((!p_flag && segsz > *fmemsz) || (p_flag &&
    449 		   mempri <= mh->mh_Node.ln_Pri && segsz > *fmemsz)) {
    450 			*fmemsz = segsz;
    451 			*fmem = (void *)seg;
    452 			mempri = mh->mh_Node.ln_Pri;
    453 		}
    454 	}
    455 	memlist.m_nseg = nmem;
    456 	Permit();
    457 }
    458 
    459 /*
    460  * Try to determine the machine ID by searching the resident module list
    461  * for modules only present on specific machines.  (Thanks, Bill!)
    462  */
    463 void
    464 get_cpuid()
    465 {
    466 	u_long *rl;
    467 	struct Resident *rm;
    468 	struct Node *rn;		/* Resource node entry */
    469 
    470 	cpuid |= SysBase->AttnFlags;	/* get FPU and CPU flags */
    471 	if (cpuid & 0xffff0000) {
    472 		switch (cpuid >> 16) {
    473 		case 500:
    474 		case 600:
    475 		case 1000:
    476 		case 1200:
    477 		case 2000:
    478 		case 3000:
    479 		case 4000:
    480 			return;
    481 		default:
    482 			printf("machine Amiga %d is not recognized\n",
    483 			    cpuid >> 16);
    484 			exit(1);
    485 		}
    486 	}
    487 	if (FindResident("A4000 Bonus") || FindResident("A1000 Bonus"))
    488 		cpuid |= 4000 << 16;
    489 	else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
    490 		cpuid |= 3000 << 16;
    491 	else if (OpenResource("card.resource")) {
    492 		/* Test for AGA? */
    493 		cpuid |= 1200 << 16;
    494 	}
    495 	/*
    496 	 * Nothing found, it's probably an A2000 or A500
    497 	 */
    498 	if ((cpuid >> 16) == 0)
    499 		cpuid |= 2000 << 16;
    500 }
    501 
    502 void
    503 get_eclock()
    504 {
    505 	/* Fix for 1.3 startups? */
    506 	if (SysBase->LibNode.lib_Version > 36)
    507 		eclock_freq = SysBase->ex_EClockFrequency;
    508 	else
    509 		eclock_freq = (GfxBase->DisplayFlags & PAL) ?
    510 		    709379 : 715909;
    511 }
    512 
    513 void
    514 get_AGA()
    515 {
    516 	/*
    517 	 * Determine if an AGA mode is active
    518 	 */
    519 }
    520 
    521 
    522 asm("
    523 	.set	ABSEXECBASE,4
    524 
    525 	.text
    526 	.globl	_startit
    527 
    528 _startit:
    529 	movel	sp,a3
    530 	movel	4:w,a6
    531 	lea	pc@(start_super-.+2),a5
    532 	jmp	a6@(-0x1e)		| supervisor-call
    533 
    534 start_super:
    535 	movew	#0x2700,sr
    536 
    537 	| the BSD kernel wants values into the following registers:
    538 	| a0:  fastmem-start
    539 	| d0:  fastmem-size
    540 	| d1:  chipmem-size
    541 	| d3:  Amiga specific flags
    542 	| d4:  E clock frequency
    543 	| d5:  AttnFlags (cpuid)
    544 	| d7:  boothowto
    545 	| a4:  esym location
    546 	| a2:  Inhibit sync flags
    547 	| All other registers zeroed for possible future requirements.
    548 
    549 	lea	pc@(_startit-.+2),sp	| make sure we have a good stack ***
    550 	movel	a3@(4),a1		| loaded kernel
    551 	movel	a3@(8),d2		| length of loaded kernel
    552 |	movel	a3@(12),sp		| entry point in stack pointer
    553 	movel	a3@(12),sp@-		| push entry point		***
    554 	movel	a3@(16),a0		| fastmem-start
    555 	movel	a3@(20),d0		| fastmem-size
    556 	movel	a3@(24),d1		| chipmem-size
    557 	movel	a3@(28),d7		| boothowto
    558 	movel	a3@(32),a4		| esym
    559 	movel	a3@(36),d5		| cpuid
    560 	movel	a3@(40),d4		| E clock frequency
    561 	movel	a3@(44),d3		| Amiga flags
    562 	movel	a3@(48),a2		| Inhibit sync flags
    563 	subl	a5,a5			| target, load to 0
    564 
    565 	btst	#3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
    566 	beq	not040
    567 
    568 | Turn off 68040 MMU
    569 
    570 	.word 0x4e7b,0xd003		| movec a5,tc
    571 	.word 0x4e7b,0xd806		| movec a5,urp
    572 	.word 0x4e7b,0xd807		| movec a5,srp
    573 	.word 0x4e7b,0xd004		| movec a5,itt0
    574 	.word 0x4e7b,0xd005		| movec a5,itt1
    575 	.word 0x4e7b,0xd006		| movec a5,dtt0
    576 	.word 0x4e7b,0xd007		| movec a5,dtt1
    577 	bra	nott
    578 
    579 not040:
    580 	lea	pc@(zero-.+2),a3
    581 	pmove	a3@,tc			| Turn off MMU
    582 	lea	pc@(nullrp-.+2),a3
    583 	pmove	a3@,crp			| Turn off MMU some more
    584 	pmove	a3@,srp			| Really, really, turn off MMU
    585 
    586 | Turn off 68030 TT registers
    587 
    588 	btst	#2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
    589 	beq	nott			| Skip TT registers if not 68030
    590 	lea	pc@(zero-.+2),a3
    591 	.word 0xf013,0x0800		| pmove a3@,tt0 (gas only knows about 68851 ops..)
    592 	.word 0xf013,0x0c00		| pmove a3@,tt1 (gas only knows about 68851 ops..)
    593 
    594 nott:
    595 
    596 	movew	#(1<<9),0xdff096	| disable DMA
    597 
    598 L0:
    599 	moveb	a1@+,a5@+
    600 	subl	#1,d2
    601 	bcc	L0
    602 
    603 
    604 	moveq	#0,d2			| zero out unused registers
    605 	moveq	#0,d6			| (might make future compatibility
    606 	movel	d6,a1			|  would have known contents)
    607 	movel	d6,a3
    608 	movel	d6,a5
    609 	movel	d6,a6
    610 |	jmp	sp@			| jump to kernel entry point
    611 	rts				| enter kernel at address on stack ***
    612 
    613 
    614 | A do-nothing MMU root pointer (includes the following long as well)
    615 
    616 nullrp:	.long	0x7fff0001
    617 zero:	.long	0
    618 
    619 
    620 ");
    621 
    622 void
    623 usage()
    624 {
    625 	fprintf(stderr, "usage: %s [-abhkptADSV] [-c machine] [-m mem] [-n mode] [-I sync-inhibit] kernel\n",
    626 	    program_name);
    627 	exit(1);
    628 }
    629 
    630 
    631 void
    632 verbose_usage()
    633 {
    634 	fprintf(stderr, "
    635 NAME
    636 \t%s - loads NetBSD from amiga dos.
    637 SYNOPSIS
    638 \t%s [-abhkptDSV] [-c machine] [-m mem] [-n flags] kernel
    639 OPTIONS
    640 \t-a  Boot up to multiuser mode.
    641 \t-A  Use AGA display mode, if available.
    642 \t-b  Ask for which root device.
    643 \t    Its possible to have multiple roots and choose between them.
    644 \t-c  Set machine type. [e.g 3000]
    645 \t-D  Enter debugger
    646 \t-h  This help message.
    647 \t-I  Inhibit sync negotiation. Option value is bit-encoded targets.
    648 \t-k  Reserve the first 4M of fast mem [Some one else
    649 \t    is going to have to answer what that it is used for].
    650 \t-m  Tweak amount of available memory, for finding minimum amount
    651 \t    of memory required to run. Sets fastmem size to specified
    652 \t    size in Kbytes.
    653 \t-n  Enable multiple non-contiguous memory: value = 0 (disabled),
    654 \t    1 (two segments), 2 (all avail segments), 3 (same as 2?).
    655 \t-p  Use highest priority fastmem segement instead of the largest
    656 \t    segment. The higher priority segment is usually faster
    657 \t    (i.e. 32 bit memory), but some people have smaller amounts
    658 \t    of 32 bit memory.
    659 \t-S  Include kernel symbol table.
    660 \t-t  This is a *test* option.  It prints out the memory
    661 \t    list information being passed to the kernel and also
    662 \t    exits without actually starting NetBSD.
    663 \t-V  Version of loadbsd program.
    664 HISTORY
    665 \tThis version supports Kernel version 720 +\n",
    666       program_name, program_name);
    667       exit(1);
    668 }
    669 
    670 
    671 void
    672 _Vdomessage(doexit, eval, doerrno, fmt, args)
    673 	int doexit, doerrno, eval;
    674 	const char *fmt;
    675 	va_list args;
    676 {
    677 	fprintf(stderr, "%s: ", program_name);
    678 	if (fmt) {
    679 		vfprintf(stderr, fmt, args);
    680 		fprintf(stderr, ": ");
    681 	}
    682 	if (doerrno && errno < sys_nerr) {
    683 		fprintf(stderr, "%s", strerror(errno));
    684 		if (errno == EINTR || errno == 0) {
    685 			int  sigs;
    686 			sigpending((sigset_t *)&sigs);
    687 			printf("%x\n", sigs);
    688 		}
    689 	}
    690 	fprintf(stderr, "\n");
    691 	if (doexit)
    692 		exit(eval);
    693 }
    694 
    695 void
    696 err(int eval, const char *fmt, ...)
    697 {
    698 	va_list ap;
    699 	va_start(ap, fmt);
    700 	_Vdomessage(1, eval, 1, fmt, ap);
    701 	/*NOTREACHED*/
    702 }
    703 
    704 void
    705 errx(int eval, const char *fmt, ...)
    706 {
    707 	va_list ap;
    708 	va_start(ap, fmt);
    709 	_Vdomessage(1, eval, 0, fmt, ap);
    710 	/*NOTREACHED*/
    711 }
    712 
    713 void
    714 warn(const char *fmt, ...)
    715 {
    716 	va_list ap;
    717 	va_start(ap, fmt);
    718 	_Vdomessage(0, 0, 1, fmt, ap);
    719 	va_end(ap);
    720 }
    721 
    722 void
    723 warnx(const char *fmt, ...)
    724 {
    725 	va_list ap;
    726 	va_start(ap, fmt);
    727 	_Vdomessage(0, 0, 0, fmt, ap);
    728 	va_end(ap);
    729 }
    730