loadbsd.c revision 1.20
1/*	$NetBSD: loadbsd.c,v 1.20 1996/06/26 15:53:07 is 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
71void err __P((int, const char *, ...));
72void errx __P((int, const char *, ...));
73void warn __P((const char *, ...));
74void warnx __P((const char *, ...));
75#endif
76
77/*
78 *	Version history:
79 *	1.x	Kernel startup interface 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 startup interface version - to
103 *		support loading kernel image to fastmem rather than chipmem.
104 *	2.13	04/15/96 - Direct load to fastmem.
105 *		Add -Z flag to force chipmem load.
106 *		Moved test mode exit to later - kernel image is created
107 *		and startup interface version checked in test mode.
108 *		Add -s flag for compatibility to bootblock loader.
109 *		05/02/96 - Add a maximum startup interface version level
110 *		to allow future kernel compatibility.
111 *	2.14	06/26/96 is - Add first version of kludges needed to
112 *		boot on DraCos. This can probably be done a bit more cleanly
113 *		using TTRs, but it works for now.
114 */
115static const char _version[] = "$VER: LoadBSD 2.14 (26.6.96)";
116
117/*
118 * Kernel startup interface version
119 *	1:	first version of loadbsd
120 *	2:	needs esym location passed in a4
121 *	3:	load kernel image into fastmem rather than chipmem
122 *	MAX:	highest version with backward compatibility.
123 */
124#define KERNEL_STARTUP_VERSION	3
125#define	KERNEL_STARTUP_VERSION_MAX	9
126
127#define DRACOREVISION (*(UBYTE *)0x02000009)
128#define DRACOMMUMARGIN 0x200000
129
130#define MAXMEMSEG	16
131struct boot_memlist {
132	u_int	m_nseg; /* num_mem; */
133	struct boot_memseg {
134		u_int	ms_start;
135		u_int	ms_size;
136		u_short	ms_attrib;
137		short	ms_pri;
138	} m_seg[MAXMEMSEG];
139};
140struct boot_memlist memlist;
141struct boot_memlist *kmemlist;
142
143
144void get_mem_config __P((void **, u_long *, u_long *));
145void get_cpuid __P((void));
146void get_eclock __P((void));
147void get_AGA __P((void));
148void usage __P((void));
149void verbose_usage __P((void));
150void Version __P((void));
151void startit __P((void *, u_long, u_long, void *, u_long, u_long, int, void *,
152		int, int, u_long, u_long, int));
153void startit_end __P((void));
154
155extern struct ExecBase *SysBase;
156extern char *optarg;
157extern int optind;
158
159int k_flag;
160int p_flag;
161int t_flag;
162int reqmemsz;
163int S_flag;
164u_long I_flag;
165int Z_flag;
166u_long cpuid;
167long eclock_freq;
168long amiga_flags;
169char *program_name;
170char *kname;
171struct ExpansionBase *ExpansionBase;
172struct GfxBase *GfxBase;
173u_char *kp;
174int ksize;
175
176int
177main(argc, argv)
178	int argc;
179	char **argv;
180{
181	struct exec e;
182	struct ConfigDev *cd, *kcd;
183	u_long fmemsz, cmemsz;
184	int fd, boothowto, textsz, stringsz, ncd, i, mem_ix, ch;
185	u_short *kvers;
186	int *nkcd;
187	void *fmem;
188	char *esym;
189	void (*start_it) __P((void *, u_long, u_long, void *, u_long, u_long,
190	     int, void *, int, int, u_long, u_long, int)) = startit;
191
192	program_name = argv[0];
193	boothowto = RB_SINGLE;
194
195	if (argc < 2)
196		usage();
197	if ((GfxBase = (void *)OpenLibrary(GRAPHICSNAME, 0)) == NULL)
198		err(20, "can't open graphics library");
199	if ((ExpansionBase=(void *)OpenLibrary(EXPANSIONNAME, 0)) == NULL)
200		err(20, "can't open expansion library");
201
202	while ((ch = getopt(argc, argv, "aAbc:DhI:km:n:ptsSVZ")) != EOF) {
203		switch (ch) {
204		case 'k':
205			k_flag = 1;
206			break;
207		case 'a':
208			boothowto &= ~(RB_SINGLE);
209			boothowto |= RB_AUTOBOOT;
210			break;
211		case 'b':
212			boothowto |= RB_ASKNAME;
213			break;
214		case 'p':
215			p_flag = 1;
216			break;
217		case 't':
218			t_flag = 1;
219			break;
220		case 'm':
221			reqmemsz = atoi(optarg) * 1024;
222			break;
223		case 's':
224			boothowto &= ~(RB_AUTOBOOT);
225			boothowto |= RB_SINGLE;
226			break;
227		case 'V':
228			fprintf(stderr,"%s\n",_version + 6);
229			break;
230		case 'S':
231			S_flag = 1;
232			break;
233		case 'D':
234			boothowto |= RB_KDB;
235			break;
236		case 'c':
237			cpuid = atoi(optarg) << 16;
238			break;
239		case 'A':
240			amiga_flags |= 1;
241			break;
242		case 'n':
243			i = atoi(optarg);
244			if (i >= 0 && i <= 3)
245				amiga_flags |= i << 1;
246			else
247				err(20, "-n option must be 0, 1, 2, or 3");
248			break;
249		case 'I':
250			I_flag = strtoul(optarg, NULL, 16);
251			break;
252		case 'Z':
253			Z_flag = 1;
254			break;
255		case 'h':
256			verbose_usage();
257		default:
258			usage();
259		}
260	}
261	argc -= optind;
262	argv += optind;
263
264	if (argc != 1)
265		usage();
266	kname = argv[0];
267
268	if ((fd = open(kname, 0)) < 0)
269		err(20, "open");
270	if (read(fd, &e, sizeof(e)) != sizeof(e))
271		err(20, "reading exec");
272	if (e.a_magic != NMAGIC)
273		err(20, "unknown binary");
274
275	for (cd = 0, ncd = 0; cd = FindConfigDev(cd, -1, -1); ncd++)
276		;
277	get_cpuid();
278	get_mem_config(&fmem, &fmemsz, &cmemsz);
279	get_eclock();
280	get_AGA();
281
282	textsz = (e.a_text + __LDPGSZ - 1) & (-__LDPGSZ);
283	esym = NULL;
284	ksize = textsz + e.a_data + e.a_bss + ncd * sizeof(*cd)
285	    + 4 + memlist.m_nseg * sizeof(struct boot_memseg) + 4;
286
287	/*
288	 * get symbol table size & string size
289	 * (should check kernel version to see if it will handle it)
290	 */
291	if (S_flag && e.a_syms) {
292		if (lseek(fd, e.a_text + e.a_data + e.a_syms, SEEK_CUR) <= 0
293		    || read(fd, &stringsz, 4) != 4
294		    || lseek(fd, sizeof(e), SEEK_SET) < 0)
295			err(20, "lseek for symbols");
296		ksize += e.a_syms + 4 + ((stringsz + 3) & ~3);
297	}
298
299	kp = (u_char *)AllocMem(ksize + ((char *)startit_end - (char *)startit) + 256,
300	    MEMF_FAST|MEMF_REVERSE);
301	if (t_flag) {
302		for (i = 0; i < memlist.m_nseg; ++i) {
303			printf("mem segment %d: start=%08lx size=%08lx"
304			    " attribute=%04lx pri=%d\n",
305			    i + 1, memlist.m_seg[i].ms_start,
306			    memlist.m_seg[i].ms_size,
307			    memlist.m_seg[i].ms_attrib,
308			    memlist.m_seg[i].ms_pri);
309		}
310		printf("kernel size: %d\n", ksize);
311	}
312	if (kp == NULL)
313		err(20, "failed malloc %d\n", ksize);
314
315	if (read(fd, kp, e.a_text) != e.a_text
316	    || read(fd, kp + textsz, e.a_data) != e.a_data)
317		err(20, "unable to read kernel image\n");
318
319	if (k_flag) {
320		fmem += 4 * 1024 * 1024;
321		fmemsz -= 4 * 1024 * 1024;
322	}
323
324	if (reqmemsz && reqmemsz <= fmemsz)
325		fmemsz = reqmemsz;
326	if (boothowto & RB_AUTOBOOT)
327		printf("Autobooting...");
328	if (boothowto & RB_ASKNAME)
329		printf("Askboot...");
330
331	printf("Using %d%c FASTMEM at 0x%x, %dM CHIPMEM\n",
332	    (fmemsz & 0xfffff) ? fmemsz >> 10 : fmemsz >> 20,
333	    (fmemsz & 0xfffff) ? 'K' : 'M', fmem, cmemsz >> 20);
334	kvers = (u_short *)(kp + e.a_entry - 2);
335	if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73)
336		err(20, "newer loadbsd required: %d\n", *kvers);
337	if (*kvers > KERNEL_STARTUP_VERSION) {
338		printf("****************************************************\n");
339		printf("*** Notice:  this kernel has features which require\n");
340		printf("*** a newer version of loadbsd.  To allow the use of\n");
341		printf("*** any newer features or capabilities, you should\n");
342		printf("*** update to a newer version of loadbsd\n");
343		printf("****************************************************\n");
344		sleep(3);	/* even more time to see that message */
345	}
346	if ((cpuid & AFB_68020) == 0)
347		err(20, "cpu not supported");
348	/*
349	 * give them a chance to read the information...
350	 */
351	sleep(2);
352
353	bzero(kp + textsz + e.a_data, e.a_bss);
354	/*
355	 * If symbols wanted (and kernel can handle them),
356	 * load symbol table & strings and set esym to end.
357	 */
358	nkcd = (int *)(kp + textsz + e.a_data + e.a_bss);
359	if (*kvers != 0x4e73 && *kvers > 1 && S_flag && e.a_syms) {
360		*nkcd++ = e.a_syms;
361		read(fd, (char *)nkcd, e.a_syms);
362		nkcd = (int *)((char *)nkcd + e.a_syms);
363		read(fd, (char *)nkcd, stringsz);
364		    nkcd = (int*)((char *)nkcd + ((stringsz + 3) & ~3));
365		    esym = (char *)(textsz + e.a_data + e.a_bss
366		    + e.a_syms + 4 + ((stringsz + 3) & ~3));
367	}
368	*nkcd = ncd;
369
370	kcd = (struct ConfigDev *)(nkcd + 1);
371	while(cd = FindConfigDev(cd, -1, -1)) {
372		*kcd = *cd;
373		if (((cpuid >> 24) == 0x7d) &&
374		    ((u_long)kcd->cd_BoardAddr < 0x1000000)) {
375			if (t_flag)
376				printf("Transformed Z2 device from %08lx ",
377				    kcd->cd_BoardAddr);
378			kcd->cd_BoardAddr += 0x3000000;
379
380			if (t_flag)
381				printf("to %08lx\n", kcd->cd_BoardAddr);
382		}
383		++kcd;
384	}
385
386	kmemlist = (struct boot_memlist *)kcd;
387	kmemlist->m_nseg = memlist.m_nseg;
388	for (mem_ix = 0; mem_ix < memlist.m_nseg; mem_ix++)
389		kmemlist->m_seg[mem_ix] = memlist.m_seg[mem_ix];
390
391	if (*kvers > 2 && Z_flag == 0) {
392		/*
393		 * Kernel supports direct load to fastmem, and the -Z
394		 * option was not specified.  Copy startup code to end
395		 * of kernel image and set start_it.
396		 */
397		if ((void *)kp < fmem) {
398			printf("Kernel at %08lx, Fastmem used at %08lx\n",
399			    kp, fmem);
400			errx(20, "Can't copy downwards yet.");
401		}
402		memcpy(kp + ksize + 256, (char *)startit,
403		    (char *)startit_end - (char *)startit);
404		CacheClearU();
405		start_it = (void (*)())kp + ksize + 256;
406		printf("*** Loading from %08lx to Fastmem %08lx ***\n",
407		    kp, fmem);
408		sleep(2);
409	} else {
410		/*
411		 * Either the kernel doesn't suppport loading directly to
412		 * fastmem or the -Z flag was given.  Verify kernel image
413		 * fits into chipmem.
414		 */
415		if (ksize >= cmemsz) {
416			printf("Kernel size %d exceeds Chip Memory of %d\n",
417			    ksize, cmemsz);
418			err(20, "Insufficient Chip Memory for kernel");
419		}
420		Z_flag = 1;
421		printf("*** Loading from %08lx to Chipmem ***\n");
422	}
423
424	/*
425	 * if test option set, done
426	 */
427	if (t_flag) {
428		if (kp)
429			FreeMem(kp, ksize + ((char *)startit_end
430			    - (char *)startit) + 256);
431		exit(0);
432	}
433
434	/*
435	 * XXX AGA startup - may need more
436	 */
437	LoadView(NULL);		/* Don't do this if AGA active? */
438	start_it(kp, ksize, e.a_entry, fmem, fmemsz, cmemsz, boothowto, esym,
439	    cpuid, eclock_freq, amiga_flags, I_flag, Z_flag == 0);
440	/*NOTREACHED*/
441}
442
443void
444get_mem_config(fmem, fmemsz, cmemsz)
445	void **fmem;
446	u_long *fmemsz, *cmemsz;
447{
448	struct MemHeader *mh, *nmh;
449	u_int segsz, seg, eseg, nmem, nseg, nsegsz;
450	u_int tseg, tsegsz;
451	char mempri;
452
453	nmem = 0;
454	mempri = -128;
455	*fmemsz = 0;
456	*cmemsz = 0;
457
458	/*
459	 * walk thru the exec memory list
460	 */
461	Forbid();
462	for (mh  = (void *) SysBase->MemList.lh_Head;
463	    nmh = (void *) mh->mh_Node.ln_Succ; mh = nmh) {
464
465		nseg = (u_int)mh->mh_Lower;
466		nsegsz = (u_int)mh->mh_Upper - nseg;
467
468		segsz = nsegsz;
469		seg = (u_int)CachePreDMA((APTR)nseg, (LONG *)&segsz, 0L);
470		nsegsz -= segsz, nseg += segsz;
471		for (;segsz;
472		    segsz = nsegsz,
473		    seg = (u_int)CachePreDMA((APTR)nseg, (LONG *)&segsz, DMA_Continue),
474		    nsegsz -= segsz, nseg += segsz, ++nmem) {
475
476			if (t_flag)
477				printf("Translated %08x sz %08x to %08x sz %08x\n",
478				    nseg - segsz, nsegsz + segsz, seg, segsz);
479
480			eseg = seg + segsz;
481
482
483			if ((cpuid >> 24) == 0x7D) {
484				/* DraCo MMU table kludge */
485
486				segsz = ((segsz -1) | 0xfffff) + 1;
487				seg = eseg - segsz;
488
489				/*
490				 * Only use first SIMM to boot; we know it is VA==PA.
491				 * Enter into table and continue. Yes,
492				 * this is ugly.
493				 */
494				if (seg != 0x40000000) {
495					memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
496					memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
497					memlist.m_seg[nmem].ms_size = segsz;
498					memlist.m_seg[nmem].ms_start = seg;
499					++nmem;
500					continue;
501				}
502
503				memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
504				memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
505				memlist.m_seg[nmem].ms_size = DRACOMMUMARGIN;
506				memlist.m_seg[nmem].ms_start = seg;
507
508				++nmem;
509				seg += DRACOMMUMARGIN;
510				segsz -= DRACOMMUMARGIN;
511			}
512
513			memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
514			memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
515			memlist.m_seg[nmem].ms_size = segsz;
516			memlist.m_seg[nmem].ms_start = seg;
517
518			if ((mh->mh_Attributes & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) {
519				/*
520				 * there should hardly be more than one entry for
521				 * chip mem, but handle it the same nevertheless
522				 * cmem always starts at 0, so include vector area
523				 */
524				memlist.m_seg[nmem].ms_start = seg = 0;
525				/*
526				 * round to multiple of 512K
527				 */
528				segsz = (segsz + 512 * 1024 - 1) & -(512 * 1024);
529				memlist.m_seg[nmem].ms_size = segsz;
530				if (segsz > *cmemsz)
531					*cmemsz = segsz;
532				continue;
533			}
534			/*
535			 * some heuristics..
536			 */
537			seg &= -__LDPGSZ;
538			eseg = (eseg + __LDPGSZ - 1) & -__LDPGSZ;
539
540			/*
541			 * get the mem back stolen by incore kickstart on
542			 * A3000 with V36 bootrom.
543			 */
544			if (eseg == 0x07f80000)
545				eseg = 0x08000000;
546
547			/*
548			 * or by zkick on a A2000.
549			 */
550			if (seg == 0x280000 &&
551			    strcmp(mh->mh_Node.ln_Name, "zkick memory") == 0)
552				seg = 0x200000;
553
554			segsz = eseg - seg;
555			memlist.m_seg[nmem].ms_start = seg;
556			memlist.m_seg[nmem].ms_size = segsz;
557			/*
558			 *  If this segment is smaller than 2M,
559			 *  don't use it to load the kernel
560			 */
561			if (segsz < 2 * 1024 * 1024)
562				continue;
563			/*
564			 * if p_flag is set, select memory by priority
565			 * instead of size
566			 */
567			if ((!p_flag && segsz > *fmemsz) || (p_flag &&
568			   mempri <= mh->mh_Node.ln_Pri && segsz > *fmemsz)) {
569				*fmemsz = segsz;
570				*fmem = (void *)seg;
571				mempri = mh->mh_Node.ln_Pri;
572			}
573
574		}
575	}
576	memlist.m_nseg = nmem;
577	Permit();
578}
579
580/*
581 * Try to determine the machine ID by searching the resident module list
582 * for modules only present on specific machines.  (Thanks, Bill!)
583 */
584void
585get_cpuid()
586{
587	u_long *rl;
588	struct Resident *rm;
589	struct Node *rn;		/* Resource node entry */
590
591	cpuid |= SysBase->AttnFlags;	/* get FPU and CPU flags */
592	if (cpuid & 0xffff0000) {
593		if ((cpuid & 0xff000000) == 0x7D)
594			return;
595
596		switch (cpuid >> 16) {
597		case 500:
598		case 600:
599		case 1000:
600		case 1200:
601		case 2000:
602		case 3000:
603		case 4000:
604			return;
605		default:
606			printf("machine Amiga %d is not recognized\n",
607			    cpuid >> 16);
608			exit(1);
609		}
610	}
611	if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
612	    || FindResident("A1000 Bonus"))
613		cpuid |= 4000 << 16;
614	else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
615		cpuid |= 3000 << 16;
616	else if (OpenResource("card.resource")) {
617		/* Test for AGA? */
618		cpuid |= 1200 << 16;
619	} else if (OpenResource("draco.resource")) {
620		cpuid |= (32000 | DRACOREVISION) << 16;
621	}
622	/*
623	 * Nothing found, it's probably an A2000 or A500
624	 */
625	if ((cpuid >> 16) == 0)
626		cpuid |= 2000 << 16;
627}
628
629void
630get_eclock()
631{
632	/* Fix for 1.3 startups? */
633	if (SysBase->LibNode.lib_Version > 36)
634		eclock_freq = SysBase->ex_EClockFrequency;
635	else
636		eclock_freq = (GfxBase->DisplayFlags & PAL) ?
637		    709379 : 715909;
638}
639
640void
641get_AGA()
642{
643	/*
644	 * Determine if an AGA mode is active
645	 */
646}
647
648
649asm("
650	.set	ABSEXECBASE,4
651
652	.text
653	.globl	_startit
654
655_startit:
656	movel	sp,a3
657	movel	4:w,a6
658	lea	pc@(start_super),a5
659	jmp	a6@(-0x1e)		| supervisor-call
660
661start_super:
662	movew	#0x2700,sr
663
664	| the BSD kernel wants values into the following registers:
665	| a0:  fastmem-start
666	| d0:  fastmem-size
667	| d1:  chipmem-size
668	| d3:  Amiga specific flags
669	| d4:  E clock frequency
670	| d5:  AttnFlags (cpuid)
671	| d7:  boothowto
672	| a4:  esym location
673	| a2:  Inhibit sync flags
674	| All other registers zeroed for possible future requirements.
675
676	lea	pc@(_startit),sp	| make sure we have a good stack ***
677
678	movel	a3@(4),a1		| loaded kernel
679	movel	a3@(8),d2		| length of loaded kernel
680|	movel	a3@(12),sp		| entry point in stack pointer
681	movel	a3@(12),a6		| push entry point		***
682	movel	a3@(16),a0		| fastmem-start
683	movel	a3@(20),d0		| fastmem-size
684	movel	a3@(24),d1		| chipmem-size
685	movel	a3@(28),d7		| boothowto
686	movel	a3@(32),a4		| esym
687	movel	a3@(36),d5		| cpuid
688	movel	a3@(40),d4		| E clock frequency
689	movel	a3@(44),d3		| Amiga flags
690	movel	a3@(48),a2		| Inhibit sync flags
691	movel	a3@(52),d6		| Load to fastmem flag
692	subl	a5,a5			| target, load to 0
693
694	cmpb	#0x7D,a3@(36)		| is it DraCo?
695	beq	nott			| yes, switch off MMU later
696
697					| no, it is an Amiga:
698
699|	movew	#0xf00,0xdff180		|red
700|	moveb	#0,0x200003c8
701|	moveb	#63,0x200003c9
702|	moveb	#0,0x200003c9
703|	moveb	#0,0x200003c9
704
705	movew	#(1<<9),0xdff096	| disable DMA on Amigas.
706
707| ------ mmu off start -----
708
709	btst	#3,d5			| AFB_68040,SysBase->AttnFlags
710	beq	not040
711
712| Turn off 68040/060 MMU
713
714	subl	a3,a3
715	.word 0x4e7b,0xb003		| movec a3,tc
716	.word 0x4e7b,0xb806		| movec a3,urp
717	.word 0x4e7b,0xb807		| movec a3,srp
718	.word 0x4e7b,0xb004		| movec a3,itt0
719	.word 0x4e7b,0xb005		| movec a3,itt1
720	.word 0x4e7b,0xb006		| movec a3,dtt0
721	.word 0x4e7b,0xb007		| movec a3,dtt1
722	bra	nott
723
724not040:
725	lea	pc@(zero),a3
726	pmove	a3@,tc			| Turn off MMU
727	lea	pc@(nullrp),a3
728	pmove	a3@,crp			| Turn off MMU some more
729	pmove	a3@,srp			| Really, really, turn off MMU
730
731| Turn off 68030 TT registers
732
733	btst	#2,d5			| AFB_68030,SysBase->AttnFlags
734	beq	nott			| Skip TT registers if not 68030
735	lea	pc@(zero),a3
736	.word 0xf013,0x0800		| pmove a3@,tt0 (gas only knows about 68851 ops..)
737	.word 0xf013,0x0c00		| pmove a3@,tt1 (gas only knows about 68851 ops..)
738
739nott:
740| ---- mmu off end ----
741|	movew	#0xf60,0xdff180		| orange
742|	moveb	#0,0x200003c8
743|	moveb	#63,0x200003c9
744|	moveb	#24,0x200003c9
745|	moveb	#0,0x200003c9
746
747| ---- copy kernel start ----
748
749	tstl	d6			| Can we load to fastmem?
750	beq	L0			| No, leave destination at 0
751	movl	a0,a5			| Move to start of fastmem chunk
752	addl	a0,a6			| relocate kernel entry point
753L0:
754	movl	a1@+,a5@+
755	subl	#4,d2
756	bcc	L0
757
758	lea	pc@(ckend:w),a1
759	movl	a5,sp@-
760	movl	#_startit_end - ckend,d2
761L2:
762	movl	a1@+,a5@+
763	subl	#4,d2
764	bcc	L2
765
766	btst	#3,d5
767	jeq	L1
768	.word	0xf4f8
769L1:	movql	#0,d2			| switch off cache to ensure we use
770	movec	d2,cacr			| valid kernel data
771
772|	movew	#0xFF0,0xdff180		| yellow
773|	moveb	#0,0x200003c8
774|	moveb	#63,0x200003c9
775|	moveb	#0,0x200003c9
776|	moveb	#0,0x200003c9
777	rts
778
779| ---- copy kernel emd ----
780
781ckend:
782|	movew	#0x0ff,0xdff180		| petrol
783|	moveb	#0,0x200003c8
784|	moveb	#0,0x200003c9
785|	moveb	#63,0x200003c9
786|	moveb	#63,0x200003c9
787
788	movl	d5,d2
789	roll	#8,d2
790	cmpb	#0x7D,d2
791	jne	noDraCo
792
793| DraCo: switch off MMU now:
794
795	subl	a3,a3
796	.word 0x4e7b,0xb003		| movec a3,tc
797	.word 0x4e7b,0xb806		| movec a3,urp
798	.word 0x4e7b,0xb807		| movec a3,srp
799	.word 0x4e7b,0xb004		| movec a3,itt0
800	.word 0x4e7b,0xb005		| movec a3,itt1
801	.word 0x4e7b,0xb006		| movec a3,dtt0
802	.word 0x4e7b,0xb007		| movec a3,dtt1
803
804noDraCo:
805	moveq	#0,d2			| zero out unused registers
806	moveq	#0,d6			| (might make future compatibility
807	movel	d6,a1			|  would have known contents)
808	movel	d6,a3
809	movel	d6,a5
810	movel	a6,sp			| entry point into stack pointer
811	movel	d6,a6
812
813|	movew	#0x0F0,0xdff180		| green
814|	moveb	#0,0x200003c8
815|	moveb	#0,0x200003c9
816|	moveb	#63,0x200003c9
817|	moveb	#0,0x200003c9
818
819	jmp	sp@			| jump to kernel entry point
820
821
822| A do-nothing MMU root pointer (includes the following long as well)
823
824nullrp:	.long	0x7fff0001
825zero:	.long	0
826
827_startit_end:
828
829");
830
831void
832usage()
833{
834	fprintf(stderr, "usage: %s [-abhkpstADSVZ] [-c machine] [-m mem] [-n mode] [-I sync-inhibit] kernel\n",
835	    program_name);
836	exit(1);
837}
838
839
840void
841verbose_usage()
842{
843	fprintf(stderr, "
844NAME
845\t%s - loads NetBSD from amiga dos.
846SYNOPSIS
847\t%s [-abhkpstADSVZ] [-c machine] [-m mem] [-n flags] [-I sync-inhibit] kernel
848OPTIONS
849\t-a  Boot up to multiuser mode.
850\t-A  Use AGA display mode, if available.
851\t-b  Ask for which root device.
852\t    Its possible to have multiple roots and choose between them.
853\t-c  Set machine type. [e.g 3000; use 32000+N for DraCo rev. N]
854\t-D  Enter debugger
855\t-h  This help message.
856\t-I  Inhibit sync negotiation. Option value is bit-encoded targets.
857\t-k  Reserve the first 4M of fast mem [Some one else
858\t    is going to have to answer what that it is used for].
859\t-m  Tweak amount of available memory, for finding minimum amount
860\t    of memory required to run. Sets fastmem size to specified
861\t    size in Kbytes.
862\t-n  Enable multiple non-contiguous memory: value = 0 (disabled),
863\t    1 (two segments), 2 (all avail segments), 3 (same as 2?).
864\t-p  Use highest priority fastmem segement instead of the largest
865\t    segment. The higher priority segment is usually faster
866\t    (i.e. 32 bit memory), but some people have smaller amounts
867\t    of 32 bit memory.
868\t-s  Boot up in singleuser mode (default).
869\t-S  Include kernel symbol table.
870\t-t  This is a *test* option.  It prints out the memory
871\t    list information being passed to the kernel and also
872\t    exits without actually starting NetBSD.
873\t-V  Version of loadbsd program.
874\t-Z  Force kernel load to chipmem.
875HISTORY
876\tThis version supports Kernel version 720 +\n",
877      program_name, program_name);
878      exit(1);
879}
880
881
882void
883_Vdomessage(doexit, eval, doerrno, fmt, args)
884	int doexit, doerrno, eval;
885	const char *fmt;
886	va_list args;
887{
888	fprintf(stderr, "%s: ", program_name);
889	if (fmt) {
890		vfprintf(stderr, fmt, args);
891		fprintf(stderr, ": ");
892	}
893	if (doerrno && errno < sys_nerr) {
894		fprintf(stderr, "%s", strerror(errno));
895#if 0
896		if (errno == EINTR || errno == 0) {
897			int  sigs;
898			sigpending((sigset_t *)&sigs);
899			printf("%x\n", sigs);
900		}
901#endif
902	}
903	fprintf(stderr, "\n");
904	if (doexit) {
905		if (kp)
906			FreeMem(kp, ksize + ((char *)startit_end
907			    - (char *)startit) + 256);
908		exit(eval);
909	}
910}
911
912void
913err(int eval, const char *fmt, ...)
914{
915	va_list ap;
916	va_start(ap, fmt);
917	_Vdomessage(1, eval, 1, fmt, ap);
918	/*NOTREACHED*/
919}
920
921void
922errx(int eval, const char *fmt, ...)
923{
924	va_list ap;
925	va_start(ap, fmt);
926	_Vdomessage(1, eval, 0, fmt, ap);
927	/*NOTREACHED*/
928}
929
930void
931warn(const char *fmt, ...)
932{
933	va_list ap;
934	va_start(ap, fmt);
935	_Vdomessage(0, 0, 1, fmt, ap);
936	va_end(ap);
937}
938
939void
940warnx(const char *fmt, ...)
941{
942	va_list ap;
943	va_start(ap, fmt);
944	_Vdomessage(0, 0, 0, fmt, ap);
945	va_end(ap);
946}
947
948
949u_int
950sleep(u_int n)
951{
952	(void)TimeDelay(0L, n, 0L);
953}
954