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