xref: /netbsd-src/sys/arch/amiga/stand/loadbsd/loadbsd.c (revision 76c7fc5f6b13ed0b1508e6b313e88e59977ed78e)
1 /*	$NetBSD: loadbsd.c,v 1.36 2019/05/29 02:34:18 msaitoh 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  */
105 static 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
121 struct 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 };
130 struct boot_memlist memlist;
131 struct boot_memlist *kmemlist;
132 
133 void get_mem_config (void **, u_long *, u_long *);
134 void get_cpuid (void);
135 void get_eclock (void);
136 void get_AGA (void);
137 void usage (void);
138 void verbose_usage (void);
139 void startit (void *, u_long, u_long, void *, u_long, u_long, int, void *,
140 		int, int, u_long, u_long, int);
141 extern u_long startit_sz;
142 
143 extern char *optarg;
144 extern int optind;
145 
146 struct ExpansionBase *ExpansionBase = NULL;
147 struct GfxBase *GfxBase = NULL;
148 
149 int k_flag;
150 int p_flag;
151 int t_flag;
152 int reqmemsz;
153 int S_flag;
154 u_long I_flag;
155 int Z_flag;
156 u_long cpuid;
157 long eclock_freq;
158 long amiga_flags;
159 char *program_name;
160 u_char *kp;
161 u_long kpsz;
162 
163 void
164 exit_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 
174 int
175 main(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 support 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 
445 void
446 get_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  */
593 void
594 get_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 
636 void
637 get_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 
647 void
648 get_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 
664 start_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 
727 not040:
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 
742 nott:
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
756 L0:
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
764 L2:
765 	movl	a1@+,a5@+
766 	subl	#4,d2
767 	bcc	L2
768 
769 	btst	#3,d5
770 	jeq	L1
771 	.word	0xf4f8
772 L1:
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 
785 ckend:
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 
808 noDraCo:
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 
827 nullrp:	.long	0x7fff0001
828 zero:	.long	0
829 
830 _startit_end:
831 
832 	.data
833 _startit_sz: .long _startit_end-_startit
834 
835 	.text
836 ");
837 
838 void
839 usage(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 
846 void
847 verbose_usage(void)
848 {
849 	fprintf(stderr, "
850 NAME
851 \t%s - loads NetBSD from amiga dos.
852 SYNOPSIS
853 \t%s [-abhkpstADSVZ] [-c machine] [-m mem] [-n flags] [-I sync-inhibit] kernel
854 OPTIONS
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.
884 HISTORY
885 \tThis version supports Kernel version 720 +\n",
886       program_name, program_name);
887       exit(1);
888 }
889 
890 static 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 
904 void
905 err(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
915 void
916 errx(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 
926 void
927 warn(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
936 void
937 warnx(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