Home | History | Annotate | Line # | Download | only in loadbsd
loadbsd.c revision 1.18
      1 /*	$NetBSD: loadbsd.c,v 1.18 1996/01/28 20:01:10 chopps 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("A4000 bonus")
    488 	    || FindResident("A1000 Bonus"))
    489 		cpuid |= 4000 << 16;
    490 	else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
    491 		cpuid |= 3000 << 16;
    492 	else if (OpenResource("card.resource")) {
    493 		/* Test for AGA? */
    494 		cpuid |= 1200 << 16;
    495 	}
    496 	/*
    497 	 * Nothing found, it's probably an A2000 or A500
    498 	 */
    499 	if ((cpuid >> 16) == 0)
    500 		cpuid |= 2000 << 16;
    501 }
    502 
    503 void
    504 get_eclock()
    505 {
    506 	/* Fix for 1.3 startups? */
    507 	if (SysBase->LibNode.lib_Version > 36)
    508 		eclock_freq = SysBase->ex_EClockFrequency;
    509 	else
    510 		eclock_freq = (GfxBase->DisplayFlags & PAL) ?
    511 		    709379 : 715909;
    512 }
    513 
    514 void
    515 get_AGA()
    516 {
    517 	/*
    518 	 * Determine if an AGA mode is active
    519 	 */
    520 }
    521 
    522 
    523 asm("
    524 	.set	ABSEXECBASE,4
    525 
    526 	.text
    527 	.globl	_startit
    528 
    529 _startit:
    530 	movel	sp,a3
    531 	movel	4:w,a6
    532 	lea	pc@(start_super-.+2),a5
    533 	jmp	a6@(-0x1e)		| supervisor-call
    534 
    535 start_super:
    536 	movew	#0x2700,sr
    537 
    538 	| the BSD kernel wants values into the following registers:
    539 	| a0:  fastmem-start
    540 	| d0:  fastmem-size
    541 	| d1:  chipmem-size
    542 	| d3:  Amiga specific flags
    543 	| d4:  E clock frequency
    544 	| d5:  AttnFlags (cpuid)
    545 	| d7:  boothowto
    546 	| a4:  esym location
    547 	| a2:  Inhibit sync flags
    548 	| All other registers zeroed for possible future requirements.
    549 
    550 	lea	pc@(_startit-.+2),sp	| make sure we have a good stack ***
    551 	movel	a3@(4),a1		| loaded kernel
    552 	movel	a3@(8),d2		| length of loaded kernel
    553 |	movel	a3@(12),sp		| entry point in stack pointer
    554 	movel	a3@(12),sp@-		| push entry point		***
    555 	movel	a3@(16),a0		| fastmem-start
    556 	movel	a3@(20),d0		| fastmem-size
    557 	movel	a3@(24),d1		| chipmem-size
    558 	movel	a3@(28),d7		| boothowto
    559 	movel	a3@(32),a4		| esym
    560 	movel	a3@(36),d5		| cpuid
    561 	movel	a3@(40),d4		| E clock frequency
    562 	movel	a3@(44),d3		| Amiga flags
    563 	movel	a3@(48),a2		| Inhibit sync flags
    564 	subl	a5,a5			| target, load to 0
    565 
    566 	btst	#3,(ABSEXECBASE)@(0x129) | AFB_68040,SysBase->AttnFlags
    567 	beq	not040
    568 
    569 | Turn off 68040 MMU
    570 
    571 	.word 0x4e7b,0xd003		| movec a5,tc
    572 	.word 0x4e7b,0xd806		| movec a5,urp
    573 	.word 0x4e7b,0xd807		| movec a5,srp
    574 	.word 0x4e7b,0xd004		| movec a5,itt0
    575 	.word 0x4e7b,0xd005		| movec a5,itt1
    576 	.word 0x4e7b,0xd006		| movec a5,dtt0
    577 	.word 0x4e7b,0xd007		| movec a5,dtt1
    578 	bra	nott
    579 
    580 not040:
    581 	lea	pc@(zero-.+2),a3
    582 	pmove	a3@,tc			| Turn off MMU
    583 	lea	pc@(nullrp-.+2),a3
    584 	pmove	a3@,crp			| Turn off MMU some more
    585 	pmove	a3@,srp			| Really, really, turn off MMU
    586 
    587 | Turn off 68030 TT registers
    588 
    589 	btst	#2,(ABSEXECBASE)@(0x129) | AFB_68030,SysBase->AttnFlags
    590 	beq	nott			| Skip TT registers if not 68030
    591 	lea	pc@(zero-.+2),a3
    592 	.word 0xf013,0x0800		| pmove a3@,tt0 (gas only knows about 68851 ops..)
    593 	.word 0xf013,0x0c00		| pmove a3@,tt1 (gas only knows about 68851 ops..)
    594 
    595 nott:
    596 
    597 	movew	#(1<<9),0xdff096	| disable DMA
    598 
    599 L0:
    600 	moveb	a1@+,a5@+
    601 	subl	#1,d2
    602 	bcc	L0
    603 
    604 
    605 	moveq	#0,d2			| zero out unused registers
    606 	moveq	#0,d6			| (might make future compatibility
    607 	movel	d6,a1			|  would have known contents)
    608 	movel	d6,a3
    609 	movel	d6,a5
    610 	movel	d6,a6
    611 |	jmp	sp@			| jump to kernel entry point
    612 	rts				| enter kernel at address on stack ***
    613 
    614 
    615 | A do-nothing MMU root pointer (includes the following long as well)
    616 
    617 nullrp:	.long	0x7fff0001
    618 zero:	.long	0
    619 
    620 
    621 ");
    622 
    623 void
    624 usage()
    625 {
    626 	fprintf(stderr, "usage: %s [-abhkptADSV] [-c machine] [-m mem] [-n mode] [-I sync-inhibit] kernel\n",
    627 	    program_name);
    628 	exit(1);
    629 }
    630 
    631 
    632 void
    633 verbose_usage()
    634 {
    635 	fprintf(stderr, "
    636 NAME
    637 \t%s - loads NetBSD from amiga dos.
    638 SYNOPSIS
    639 \t%s [-abhkptDSV] [-c machine] [-m mem] [-n flags] kernel
    640 OPTIONS
    641 \t-a  Boot up to multiuser mode.
    642 \t-A  Use AGA display mode, if available.
    643 \t-b  Ask for which root device.
    644 \t    Its possible to have multiple roots and choose between them.
    645 \t-c  Set machine type. [e.g 3000]
    646 \t-D  Enter debugger
    647 \t-h  This help message.
    648 \t-I  Inhibit sync negotiation. Option value is bit-encoded targets.
    649 \t-k  Reserve the first 4M of fast mem [Some one else
    650 \t    is going to have to answer what that it is used for].
    651 \t-m  Tweak amount of available memory, for finding minimum amount
    652 \t    of memory required to run. Sets fastmem size to specified
    653 \t    size in Kbytes.
    654 \t-n  Enable multiple non-contiguous memory: value = 0 (disabled),
    655 \t    1 (two segments), 2 (all avail segments), 3 (same as 2?).
    656 \t-p  Use highest priority fastmem segement instead of the largest
    657 \t    segment. The higher priority segment is usually faster
    658 \t    (i.e. 32 bit memory), but some people have smaller amounts
    659 \t    of 32 bit memory.
    660 \t-S  Include kernel symbol table.
    661 \t-t  This is a *test* option.  It prints out the memory
    662 \t    list information being passed to the kernel and also
    663 \t    exits without actually starting NetBSD.
    664 \t-V  Version of loadbsd program.
    665 HISTORY
    666 \tThis version supports Kernel version 720 +\n",
    667       program_name, program_name);
    668       exit(1);
    669 }
    670 
    671 
    672 void
    673 _Vdomessage(doexit, eval, doerrno, fmt, args)
    674 	int doexit, doerrno, eval;
    675 	const char *fmt;
    676 	va_list args;
    677 {
    678 	fprintf(stderr, "%s: ", program_name);
    679 	if (fmt) {
    680 		vfprintf(stderr, fmt, args);
    681 		fprintf(stderr, ": ");
    682 	}
    683 	if (doerrno && errno < sys_nerr) {
    684 		fprintf(stderr, "%s", strerror(errno));
    685 		if (errno == EINTR || errno == 0) {
    686 			int  sigs;
    687 			sigpending((sigset_t *)&sigs);
    688 			printf("%x\n", sigs);
    689 		}
    690 	}
    691 	fprintf(stderr, "\n");
    692 	if (doexit)
    693 		exit(eval);
    694 }
    695 
    696 void
    697 err(int eval, const char *fmt, ...)
    698 {
    699 	va_list ap;
    700 	va_start(ap, fmt);
    701 	_Vdomessage(1, eval, 1, fmt, ap);
    702 	/*NOTREACHED*/
    703 }
    704 
    705 void
    706 errx(int eval, const char *fmt, ...)
    707 {
    708 	va_list ap;
    709 	va_start(ap, fmt);
    710 	_Vdomessage(1, eval, 0, fmt, ap);
    711 	/*NOTREACHED*/
    712 }
    713 
    714 void
    715 warn(const char *fmt, ...)
    716 {
    717 	va_list ap;
    718 	va_start(ap, fmt);
    719 	_Vdomessage(0, 0, 1, fmt, ap);
    720 	va_end(ap);
    721 }
    722 
    723 void
    724 warnx(const char *fmt, ...)
    725 {
    726 	va_list ap;
    727 	va_start(ap, fmt);
    728 	_Vdomessage(0, 0, 0, fmt, ap);
    729 	va_end(ap);
    730 }
    731