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