xref: /netbsd-src/sys/arch/amiga/stand/loadbsd/loadbsd.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
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