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