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