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