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