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