Home | History | Annotate | Line # | Download | only in loadbsd
loadbsd.c revision 1.36.2.2
      1 /*	$NetBSD: loadbsd.c,v 1.36.2.2 2023/06/03 15:07:53 martin 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 
     34 #include <exec/memory.h>
     35 #include <exec/execbase.h>
     36 #include <exec/resident.h>
     37 #include <graphics/gfxbase.h>
     38 #include <libraries/expansion.h>
     39 #include <libraries/expansionbase.h>
     40 #include <libraries/configregs.h>
     41 #include <libraries/configvars.h>
     42 #include <proto/expansion.h>
     43 #include <proto/graphics.h>
     44 #include <proto/exec.h>
     45 #include <proto/dos.h>
     46 
     47 /* Get definitions for boothowto */
     48 #include "sys/reboot.h"
     49 #include "inttypes.h"
     50 #include "loadfile.h"
     51 
     52 #undef AOUT_LDPGSZ
     53 #define AOUT_LDPGSZ 8192
     54 
     55 #undef sleep
     56 #define sleep(n) if (!t_flag) (void)Delay(50*n)
     57 
     58 /*
     59  *	Version history:
     60  *	1.x	Kernel startup interface version check.
     61  *	2.0	Added symbol table end address and symbol table support.
     62  *	2.1	03/23/94 - Round up end of fastram segment.
     63  *		Check fastram segment size for minimum of 2M.
     64  *		Use largest segment of highest priority if -p option.
     65  *		Print out fastram size in KB if not a multiple of MB.
     66  *	2.2	03/24/94 - Zero out all unused registers.
     67  *		Started version history comment.
     68  *	2.3	04/26/94 - Added -D option to enter debugger on boot.
     69  *	2.4	04/30/94 - Cpuid includes base machine type.
     70  *		Also check if CPU is capable of running NetBSD.
     71  *	2.5	05/17/94 - Add check for "A3000 bonus".
     72  *	2.6	06/05/94 - Added -c option to override machine type.
     73  *	2.7	06/15/94 - Pass E clock frequency.
     74  *	2.8	06/22/94 - Fix supervisor stack usage.
     75  *	2.9	06/26/94 - Use PAL flag for E clock freq on pre 2.0 WB
     76  *		Added AGA enable parameter
     77  *	2.10	12/22/94 - Use FindResident() & OpenResource() for machine
     78  *		type detection.
     79  *		Add -n flag & option for non-contiguous memory.
     80  *		01/28/95 - Corrected -n on usage & help messages.
     81  *	2.11	03/12/95 - Check kernel size against chip memory size.
     82  *	2.12	11/11/95 - Add -I option to inhibit synchronous transfer
     83  *		11/12/95 - New kernel startup interface version - to
     84  *		support loading kernel image to fastmem rather than chipmem.
     85  *	2.13	04/15/96 - Direct load to fastmem.
     86  *		Add -Z flag to force chipmem load.
     87  *		Moved test mode exit to later - kernel image is created
     88  *		and startup interface version checked in test mode.
     89  *		Add -s flag for compatibility to bootblock loader.
     90  *		05/02/96 - Add a maximum startup interface version level
     91  *		to allow future kernel compatibility.
     92  *	2.14	06/26/96 is - Add first version of kludges needed to
     93  *		boot on DraCos. This can probably be done a bit more cleanly
     94  *		using TTRs, but it works for now.
     95  *	2.15	07/28/96 is - Add first version of kludges needed to
     96  *		get FusionForty kickrom'd memory back. Hope this doesn't
     97  *		break anything else.
     98  *	2.16	07/08/00 - Added bootverbose support.
     99  *		01/15/03 - Plugged resource leaks.
    100  *		Fixed printf() statements.
    101  *		Ansified.
    102  *	3.0	01/16/03 - ELF support through loadfile() interface.
    103  *	3.1	07/10/11 - Added a serial console flag
    104  *		11/18/15 - (gnikl) Added detection of A600.
    105  *		Fix handling of multiple -n options.
    106  *	3.2	09/02/22 - Make it compile with modern AmigaOS gcc ports.
    107  *	3.3	01/04/22 - Loading the kernel to the highest priority memory
    108  *		segment is the default now. New option -l to revert to the
    109  *		previous behaviour of largest segment.
    110  *		New option -M to define a minimum size for the memory segment.
    111  */
    112 static const char _version[] = "$VER: LoadBSD 3.3 (01.04.2023)";
    113 
    114 /*
    115  * Kernel startup interface version
    116  *	1:	first version of loadbsd
    117  *	2:	needs esym location passed in a4
    118  *	3:	load kernel image into fastmem rather than chipmem
    119  *	MAX:	highest version with backward compatibility.
    120  */
    121 #define KERNEL_STARTUP_VERSION		3
    122 #define	KERNEL_STARTUP_VERSION_MAX	9
    123 
    124 #define DRACOREVISION (*(UBYTE *)0x02000009)
    125 #define DRACOMMUMARGIN 0x200000
    126 
    127 #define MAXMEMSEG	16
    128 struct boot_memlist {
    129 	u_int	m_nseg; /* num_mem; */
    130 	struct boot_memseg {
    131 		u_int	ms_start;
    132 		u_int	ms_size;
    133 		u_short	ms_attrib;
    134 		short	ms_pri;
    135 	} m_seg[MAXMEMSEG];
    136 };
    137 struct boot_memlist memlist;
    138 struct boot_memlist *kmemlist;
    139 
    140 void err(int eval, const char *, ...);
    141 int getopt(int, char * const [], const char *);
    142 void get_mem_config (void **, u_long *, u_long *);
    143 void get_cpuid (void);
    144 void get_eclock (void);
    145 void get_AGA (void);
    146 void usage (void);
    147 void verbose_usage (void);
    148 extern void startit (void *, u_long, u_long, void *, u_long, u_long, int, void *,
    149 		int, int, u_long, u_long, int);
    150 extern u_long startit_sz;
    151 
    152 extern char *optarg;
    153 extern int optind;
    154 
    155 struct ExpansionBase *ExpansionBase = NULL;
    156 struct GfxBase *GfxBase = NULL;
    157 
    158 u_int minmemsz = 2 * 1024 * 1024;
    159 int p_flag = 1;
    160 int k_flag;
    161 int t_flag;
    162 int reqmemsz;
    163 int S_flag;
    164 u_long I_flag;
    165 int Z_flag;
    166 u_long cpuid;
    167 long eclock_freq;
    168 long amiga_flags;
    169 char *program_name;
    170 u_char *kp;
    171 u_long kpsz;
    172 
    173 
    174 void
    175 exit_func(void)
    176 {
    177 	if (kp)
    178 		FreeMem(kp, kpsz);
    179 	if (ExpansionBase)
    180 		CloseLibrary((struct Library *)ExpansionBase);
    181 	if (GfxBase)
    182 		CloseLibrary((struct Library *)GfxBase);
    183 }
    184 
    185 int
    186 main(int argc, char **argv)
    187 {
    188 	struct ConfigDev *cd, *kcd;
    189 	u_long fmemsz, cmemsz, ksize, marks[MARK_MAX];
    190 	int boothowto, ncd, i, mem_ix, ch;
    191 	u_short kvers;
    192 	int *nkcd;
    193 	u_char *fmem;
    194 	char *esym;
    195 	void (*start_it) (void *, u_long, u_long, void *, u_long, u_long,
    196 	     int, void *, int, int, u_long, u_long, int) = startit;
    197 	char *kernel_name;
    198 
    199 	atexit(exit_func);
    200 
    201 	program_name = argv[0];
    202 	boothowto = RB_SINGLE;
    203 
    204 	if (argc < 2)
    205 		usage();
    206 
    207 	if ((GfxBase = (void *)OpenLibrary(GRAPHICSNAME, 0)) == NULL)
    208 		err(20, "can't open graphics library");
    209 	if ((ExpansionBase=(void *)OpenLibrary(EXPANSIONNAME, 0)) == NULL)
    210 		err(20, "can't open expansion library");
    211 
    212 	while ((ch = getopt(argc, argv, "aAbCc:DhI:klm:M:n:qptsSvVZ")) != -1) {
    213 		switch (ch) {
    214 		case 'k':
    215 			k_flag = 1;
    216 			break;
    217 		case 'a':
    218 			boothowto &= ~(RB_SINGLE);
    219 			boothowto |= RB_AUTOBOOT;
    220 			break;
    221 		case 'b':
    222 			boothowto |= RB_ASKNAME;
    223 			break;
    224 		case 'p':
    225 			p_flag = 1;
    226 			break;
    227 		case 'l':
    228 			p_flag = 0;
    229 			break;
    230 		case 't':
    231 			t_flag = 1;
    232 			break;
    233 		case 'm':
    234 			reqmemsz = atoi(optarg) * 1024;
    235 			break;
    236 		case 'M':
    237 			minmemsz = atoi(optarg) * 1024 * 1024;
    238 			break;
    239 		case 's':
    240 			boothowto &= ~(RB_AUTOBOOT);
    241 			boothowto |= RB_SINGLE;
    242 			break;
    243 		case 'q':
    244 			boothowto |= AB_QUIET;
    245 			break;
    246 		case 'v':
    247 			boothowto |= AB_VERBOSE;
    248 			break;
    249 		case 'V':
    250 			fprintf(stderr,"%s\n",_version + 6);
    251 			break;
    252 		case 'S':
    253 			S_flag = 1;
    254 			break;
    255 		case 'D':
    256 			boothowto |= RB_KDB;
    257 			break;
    258 		case 'c':
    259 			cpuid = atoi(optarg) << 16;
    260 			break;
    261 		case 'A':
    262 			amiga_flags |= 1;
    263 			break;
    264 		case 'n':
    265 			i = atoi(optarg);
    266 			if (i >= 0 && i <= 3) {
    267 				amiga_flags &= ~(3 << 1);
    268 				amiga_flags |= i << 1;
    269 			}
    270 			else
    271 				err(20, "-n option must be 0, 1, 2, or 3");
    272 			break;
    273 		case 'C':
    274 			amiga_flags |= (1 << 3);
    275 			break;
    276 		case 'I':
    277 			I_flag = strtoul(optarg, NULL, 16);
    278 			break;
    279 		case 'Z':
    280 			Z_flag = 1;
    281 			break;
    282 		case 'h':
    283 			verbose_usage();
    284 		default:
    285 			usage();
    286 		}
    287 	}
    288 	argc -= optind;
    289 	argv += optind;
    290 
    291 	if (argc != 1)
    292 		usage();
    293 
    294 	kernel_name = argv[0];
    295 
    296 	for (cd = 0, ncd = 0; cd = FindConfigDev(cd, -1, -1); ncd++)
    297 		;
    298 	get_cpuid();
    299 	get_mem_config((void **)&fmem, &fmemsz, &cmemsz);
    300 	get_eclock();
    301 	get_AGA();
    302 
    303 /*
    304  * XXX Call loadfile with COUNT* options to get size
    305  * XXX Allocate memory for kernel + additional data
    306  * XXX Call loadfile with LOAD* options to load text/data/symbols
    307  */
    308 	marks[MARK_START] = 0;
    309 	if (loadfile(kernel_name, marks,
    310 	    COUNT_TEXT|COUNT_TEXTA|COUNT_DATA|COUNT_BSS|
    311 	    (S_flag ? (COUNT_SYM|COUNT_HDR) : 0)) == -1) {
    312 		err(20, "unable to parse kernel image");
    313 	}
    314 	ksize = ((marks[MARK_END] + 3) & ~3)
    315 	    + sizeof(*nkcd) + ncd * sizeof(*cd)
    316 	    + sizeof(*nkcd) + memlist.m_nseg * sizeof(struct boot_memseg);
    317 
    318 	if (t_flag) {
    319 		for (i = 0; i < memlist.m_nseg; ++i) {
    320 			printf("mem segment %d: start=%08x size=%08x"
    321 			    " attribute=%04x pri=%d\n",
    322 			    i + 1,
    323 			    memlist.m_seg[i].ms_start,
    324 			    memlist.m_seg[i].ms_size,
    325 			    memlist.m_seg[i].ms_attrib,
    326 			    memlist.m_seg[i].ms_pri);
    327 		}
    328 		printf("kernel size: %lu\n", ksize);
    329 	}
    330 
    331 	kpsz = ksize + 256 + startit_sz;
    332 	kp = (u_char *)AllocMem(kpsz, MEMF_FAST|MEMF_REVERSE);
    333 	if (kp == NULL)
    334 		err(20, "failed alloc %d", ksize);
    335 
    336 	marks[MARK_START] = (u_long)kp;
    337 	if (loadfile(kernel_name, marks,
    338 	    LOAD_TEXT|LOAD_TEXTA|LOAD_DATA|LOAD_BSS|
    339 	    (S_flag ? (LOAD_SYM|LOAD_HDR) : 0)) == -1) {
    340 		err(20, "unable to load kernel image");
    341 	}
    342 	marks[MARK_END] = (marks[MARK_END] + 3) & ~3;
    343 
    344 	if (k_flag) {
    345 		fmem += 4 * 1024 * 1024;
    346 		fmemsz -= 4 * 1024 * 1024;
    347 	}
    348 	if (reqmemsz && reqmemsz <= fmemsz)
    349 		fmemsz = reqmemsz;
    350 
    351 	if (boothowto & RB_AUTOBOOT)
    352 		printf("Autobooting...");
    353 	if (boothowto & RB_ASKNAME)
    354 		printf("Askboot...");
    355 
    356 	printf("Using %lu%c FASTMEM at 0x%lx, %luM CHIPMEM\n",
    357 	    (fmemsz & 0xfffff) ? fmemsz >> 10 : fmemsz >> 20,
    358 	    (fmemsz & 0xfffff) ? 'K' : 'M', (u_long)fmem, cmemsz >> 20);
    359 
    360 	kvers = *(u_short *)(marks[MARK_ENTRY] - 2);
    361 	if (kvers == 0x4e73) kvers = 0;
    362 	if (kvers > KERNEL_STARTUP_VERSION_MAX)
    363 		err(20, "newer loadbsd required: %d\n", kvers);
    364 	if (kvers > KERNEL_STARTUP_VERSION) {
    365 		printf("****************************************************\n"
    366 		       "*** Notice:  this kernel has features which require\n"
    367 		       "*** a newer version of loadbsd.  To allow the use of\n"
    368 		       "*** any newer features or capabilities, you should\n"
    369 		       "*** update to a newer version of loadbsd\n"
    370 		       "****************************************************\n");
    371 		sleep(3);	/* even more time to see that message */
    372 	}
    373 
    374 	/*
    375 	 * give them a chance to read the information...
    376 	 */
    377 	sleep(2);
    378 
    379 	nkcd = (int *)marks[MARK_END];
    380 	esym = 0;
    381 	/*
    382 	 * If symbols loaded and kernel can handle them, set esym to end.
    383 	 */
    384 	if (marks[MARK_SYM] != marks[MARK_START]) {
    385 		if (kvers > 1)  {
    386 			esym = (void *)(marks[MARK_END] - marks[MARK_START]);
    387 		}
    388 		else {
    389 			/*
    390 			 * suppress symbols
    391 			 */
    392 			nkcd = (int *)marks[MARK_SYM];
    393 		}
    394 	}
    395 
    396 	*nkcd = ncd;
    397 	kcd = (struct ConfigDev *)(nkcd + 1);
    398 	while((cd = FindConfigDev(cd, -1, -1))) {
    399 		u_char *ba = kcd->cd_BoardAddr;
    400 
    401 		memcpy(kcd, cd, sizeof(*kcd));
    402 		if (((cpuid >> 24) == 0x7d) && ((u_long)ba < 0x1000000)) {
    403 			if (t_flag)
    404 				printf("Transformed Z2 device from %08lx ", (u_long)ba);
    405 			ba += 0x3000000;
    406 			kcd->cd_BoardAddr = ba;
    407 			if (t_flag)
    408 				printf("to %08lx\n", (u_long)ba);
    409 		}
    410 		++kcd;
    411 	}
    412 
    413 	kmemlist = (struct boot_memlist *)kcd;
    414 	kmemlist->m_nseg = memlist.m_nseg;
    415 	for (mem_ix = 0; mem_ix < memlist.m_nseg; mem_ix++)
    416 		kmemlist->m_seg[mem_ix] = memlist.m_seg[mem_ix];
    417 
    418 	if (kvers > 2 && Z_flag == 0) {
    419 		/*
    420 		 * Kernel supports direct load to fastmem, and the -Z
    421 		 * option was not specified.  Copy startup code to end
    422 		 * of kernel image and set start_it.
    423 		 */
    424 		if (ksize >= fmemsz) {
    425 			printf("Kernel size %lu exceeds best Fast Memory segment of %lu\n",
    426 			    ksize, fmemsz);
    427 			err(20, "Insufficient Fast Memory for kernel");
    428 		}
    429 		if (kp < fmem) {
    430 			printf("Kernel at %08lx, Fastmem used at %08lx\n",
    431 			    (u_long)kp, (u_long)fmem);
    432 			err(20, "Can't copy upwards yet.\nDefragment your memory and try again OR try the -p OR try the -Z options.");
    433 		}
    434 		start_it = (void (*)())(kp + ksize + 256);
    435 		memcpy((void *)start_it, (void *)startit, startit_sz);
    436 		CacheClearU();
    437 		printf("*** Loading from %08lx to Fastmem %08lx ***\n",
    438 		    (u_long)kp, (u_long)fmem);
    439 		sleep(2);
    440 	} else {
    441 		/*
    442 		 * Either the kernel doesn't support loading directly to
    443 		 * fastmem or the -Z flag was given.  Verify kernel image
    444 		 * fits into chipmem.
    445 		 */
    446 		if (ksize >= cmemsz) {
    447 			printf("Kernel size %lu exceeds Chip Memory of %lu\n",
    448 			    ksize, cmemsz);
    449 			err(20, "Insufficient Chip Memory for kernel");
    450 		}
    451 		Z_flag = 1;
    452 		printf("*** Loading from %08lx to Chipmem ***\n", (u_long)kp);
    453 	}
    454 
    455 	/*
    456 	 * if test option set, done
    457 	 */
    458 	if (t_flag) {
    459 		exit(0);
    460 	}
    461 
    462 	/*
    463 	 * XXX AGA startup - may need more
    464 	 */
    465 	LoadView(NULL);		/* Don't do this if AGA active? */
    466 	start_it(kp, ksize, marks[MARK_ENTRY] - marks[MARK_START], fmem, fmemsz, cmemsz,
    467 	    boothowto, esym, cpuid, eclock_freq, amiga_flags, I_flag, Z_flag == 0);
    468 	/*NOTREACHED*/
    469 }
    470 
    471 void
    472 get_mem_config(void **fmem, u_long *fmemsz, u_long *cmemsz)
    473 {
    474 	struct MemHeader *mh, *nmh;
    475 	u_int nmem, eseg, segsz, seg, nseg, nsegsz;
    476 	char mempri;
    477 
    478 	nmem = 0;
    479 	mempri = -128;
    480 	*fmemsz = 0;
    481 	*cmemsz = 0;
    482 	*fmem = NULL;
    483 
    484 	/*
    485 	 * walk through the exec memory list
    486 	 */
    487 	Forbid();
    488 	for (mh  = (void *) SysBase->MemList.lh_Head;
    489 	    nmh = (void *) mh->mh_Node.ln_Succ; mh = nmh) {
    490 
    491 		nseg = (u_int)mh->mh_Lower;
    492 		nsegsz = (u_int)mh->mh_Upper - nseg;
    493 
    494 		segsz = nsegsz;
    495 		seg = (u_int)CachePreDMA((APTR)nseg, (LONG *)&segsz, 0L);
    496 		nsegsz -= segsz, nseg += segsz;
    497 		for (;segsz;
    498 		    segsz = nsegsz,
    499 		    seg = (u_int)CachePreDMA((APTR)nseg, (LONG *)&segsz, DMA_Continue),
    500 		    nsegsz -= segsz, nseg += segsz, ++nmem) {
    501 
    502 			if (t_flag)
    503 				printf("Translated %08x sz %08x to %08x sz %08x\n",
    504 				    nseg - segsz, nsegsz + segsz, seg, segsz);
    505 
    506 			eseg = seg + segsz;
    507 
    508 			if ((cpuid >> 24) == 0x7D) {
    509 				/* DraCo MMU table kludge */
    510 
    511 				segsz = ((segsz -1) | 0xfffff) + 1;
    512 				seg = eseg - segsz;
    513 
    514 				/*
    515 				 * Only use first SIMM to boot; we know it is VA==PA.
    516 				 * Enter into table and continue. Yes,
    517 				 * this is ugly.
    518 				 */
    519 				if (seg != 0x40000000) {
    520 					memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
    521 					memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
    522 					memlist.m_seg[nmem].ms_size = segsz;
    523 					memlist.m_seg[nmem].ms_start = seg;
    524 					++nmem;
    525 					continue;
    526 				}
    527 
    528 				memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
    529 				memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
    530 				memlist.m_seg[nmem].ms_size = DRACOMMUMARGIN;
    531 				memlist.m_seg[nmem].ms_start = seg;
    532 
    533 				++nmem;
    534 				seg += DRACOMMUMARGIN;
    535 				segsz -= DRACOMMUMARGIN;
    536 			}
    537 
    538 			memlist.m_seg[nmem].ms_attrib = mh->mh_Attributes;
    539 			memlist.m_seg[nmem].ms_pri = mh->mh_Node.ln_Pri;
    540 			memlist.m_seg[nmem].ms_size = segsz;
    541 			memlist.m_seg[nmem].ms_start = seg;
    542 
    543 			if ((mh->mh_Attributes & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) {
    544 				/*
    545 				 * there should hardly be more than one entry for
    546 				 * chip mem, but handle it the same nevertheless
    547 				 * cmem always starts at 0, so include vector area
    548 				 */
    549 				memlist.m_seg[nmem].ms_start = seg = 0;
    550 				/*
    551 				 * round to multiple of 512K
    552 				 */
    553 				segsz = (segsz + 512 * 1024 - 1) & -(512 * 1024);
    554 				memlist.m_seg[nmem].ms_size = segsz;
    555 				if (segsz > *cmemsz)
    556 					*cmemsz = segsz;
    557 				continue;
    558 			}
    559 			/*
    560 			 * some heuristics..
    561 			 */
    562 			seg &= -AOUT_LDPGSZ;
    563 			eseg = (eseg + AOUT_LDPGSZ - 1) & -AOUT_LDPGSZ;
    564 
    565 			/*
    566 			 * get the mem back stolen by incore kickstart on
    567 			 * A3000 with V36 bootrom.
    568 			 */
    569 			if (eseg == 0x07f80000)
    570 				eseg = 0x08000000;
    571 
    572 			/*
    573 			 * or by zkick on a A2000.
    574 			 */
    575 			if (seg == 0x280000 &&
    576 			    strcmp(mh->mh_Node.ln_Name, "zkick memory") == 0)
    577 				seg = 0x200000;
    578 			/*
    579 			 * or by Fusion Forty fastrom
    580 			 */
    581 			if ((seg & ~(1024*1024-1)) == 0x11000000) {
    582 				/*
    583 				 * XXX we should test the name.
    584 				 * Unfortunately, the memory is just called
    585 				 * "32 bit memory" which isn't very specific.
    586 				 */
    587 				seg = 0x11000000;
    588 			}
    589 
    590 			segsz = eseg - seg;
    591 			memlist.m_seg[nmem].ms_start = seg;
    592 			memlist.m_seg[nmem].ms_size = segsz;
    593 			/*
    594 			 *  If this segment is smaller than minmemsz (default: 2M),
    595 			 *  don't use it to load the kernel
    596 			 */
    597 			if (segsz < minmemsz)
    598 				continue;
    599 			/*
    600 			 * if p_flag is set, select memory by priority
    601 			 * instead of size
    602 			 */
    603 			if ((!p_flag && segsz > *fmemsz) || (p_flag &&
    604 			   mempri <= mh->mh_Node.ln_Pri && segsz > *fmemsz)) {
    605 				*fmemsz = segsz;
    606 				*fmem = (void *)seg;
    607 				mempri = mh->mh_Node.ln_Pri;
    608 			}
    609 
    610 		}
    611 	}
    612 	memlist.m_nseg = nmem;
    613 	Permit();
    614 }
    615 
    616 /*
    617  * Try to determine the machine ID by searching the resident module list
    618  * for modules only present on specific machines.  (Thanks, Bill!)
    619  */
    620 void
    621 get_cpuid(void)
    622 {
    623 	cpuid |= SysBase->AttnFlags;	/* get FPU and CPU flags */
    624 	if ((cpuid & AFB_68020) == 0)
    625 		err(20, "CPU not supported");
    626 	if (cpuid & 0xffff0000) {
    627 		if ((cpuid >> 24) == 0x7D)
    628 			return;
    629 
    630 		switch (cpuid >> 16) {
    631 		case 500:
    632 		case 600:
    633 		case 1000:
    634 		case 1200:
    635 		case 2000:
    636 		case 3000:
    637 		case 4000:
    638 			return;
    639 		default:
    640 			printf("machine Amiga %lu is not recognized\n",
    641 			    cpuid >> 16);
    642 			exit(1);
    643 		}
    644 	}
    645 	if (FindResident("A4000 Bonus") || FindResident("A4000 bonus")
    646 	    || FindResident("A1000 Bonus"))
    647 		cpuid |= 4000 << 16;
    648 	else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus"))
    649 		cpuid |= 3000 << 16;
    650 	else if (OpenResource("card.resource")) {
    651 		UBYTE alicerev = *((UBYTE *)0xdff004) & 0x6f;
    652 		if (alicerev == 0x22 || alicerev == 0x23)
    653 			cpuid |= 1200 << 16;	/* AGA + PCMCIA = A1200 */
    654 		else
    655 			cpuid |= 600 << 16;	/* noAGA + PCMCIA = A600 */
    656 	} else if (OpenResource("draco.resource")) {
    657 		cpuid |= (32000 | DRACOREVISION) << 16;
    658 	}
    659 	/*
    660 	 * Nothing found, it's probably an A2000 or A500
    661 	 */
    662 	if ((cpuid >> 16) == 0)
    663 		cpuid |= 2000 << 16;
    664 }
    665 
    666 void
    667 get_eclock(void)
    668 {
    669 	/* Fix for 1.3 startups? */
    670 	if (SysBase->LibNode.lib_Version > 36)
    671 		eclock_freq = SysBase->ex_EClockFrequency;
    672 	else
    673 		eclock_freq = (GfxBase->DisplayFlags & PAL) ?
    674 		    709379 : 715909;
    675 }
    676 
    677 void
    678 get_AGA(void)
    679 {
    680 	/*
    681 	 * Determine if an AGA mode is active
    682 	 */
    683 }
    684 
    685 void
    686 usage(void)
    687 {
    688 	fprintf(stderr, "usage: %s [-abhklpstACDSVZ] [-c machine] [-m size] [-M size] [-n mode] [-I sync-inhibit] kernel\n",
    689 	    program_name);
    690 	exit(1);
    691 }
    692 
    693 void
    694 verbose_usage(void)
    695 {
    696 	fprintf(stderr, "\n\
    697 NAME\n\
    698 \t%s - loads NetBSD from amiga dos.\n\
    699 SYNOPSIS\n\
    700 \t%s [-abhklpstACDSVZ] [-c machine] [-m size] [-M size] [-n mode] [-I sync-inhibit] kernel\n\
    701 OPTIONS\n\
    702 \t-a  Boot up to multiuser mode.\n\
    703 \t-A  Use AGA display mode, if available.\n\
    704 \t-b  Ask for which root device.\n\
    705 \t    It is possible to have multiple roots and choose between them.\n\
    706 \t-c  Set machine type. [e.g 3000; use 32000+N for DraCo rev. N]\n\
    707 \t-C  Use Serial Console.\n\
    708 \t-D  Enter debugger\n\
    709 \t-h  This help message.\n\
    710 \t-I  Inhibit sync negotiation. Option value is bit-encoded targets.\n\
    711 \t-k  Reserve the first 4M of fast mem [Some one else\n\
    712 \t    is going to have to answer what that it is used for].\n\
    713 \t-l  Use the largest memory segment for loading the kernel.\n\
    714 \t-m  Tweak amount of available memory, for finding minimum amount\n\
    715 \t    of memory required to run. Sets fastmem size to specified\n\
    716 \t    size in Kbytes.\n\
    717 \t-M  Request a minimum size in Mbytes for the kernel's memory\n\
    718 \t    segment. Defaults to 2M.\n\
    719 \t-n  Enable multiple non-contiguous memory: value = 0 (disabled),\n\
    720 \t    1 (two segments), 2 (all avail segments), 3 (same as 2?).\n\
    721 \t-p  Use highest priority fastmem segment for loading the kernel.\n\
    722 \t    This is the default.\n\
    723 \t-q  Boot up in quiet mode.\n\
    724 \t-s  Boot up in singleuser mode (default).\n\
    725 \t-S  Include kernel symbol table.\n\
    726 \t-t  This is a *test* option.  It prints out the memory\n\
    727 \t    list information being passed to the kernel and also\n\
    728 \t    exits without actually starting NetBSD.\n\
    729 \t-v  Boot up in verbose mode.\n\
    730 \t-V  Version of loadbsd program.\n\
    731 \t-Z  Force kernel load to chipmem.\n\
    732 HISTORY\n\
    733 \tThis version supports Kernel version 720 +\n",
    734       program_name, program_name);
    735       exit(1);
    736 }
    737 
    738 static void
    739 _Vdomessage(int doerrno, const char *fmt, va_list args)
    740 {
    741 	fprintf(stderr, "%s: ", program_name);
    742 	if (fmt) {
    743 		vfprintf(stderr, fmt, args);
    744 		fprintf(stderr, ": ");
    745 	}
    746 	if (doerrno) {
    747 		fprintf(stderr, "%s", strerror(errno));
    748 	}
    749 	fprintf(stderr, "\n");
    750 }
    751 
    752 void
    753 err(int eval, const char *fmt, ...)
    754 {
    755 	va_list ap;
    756 	va_start(ap, fmt);
    757 	_Vdomessage(1, fmt, ap);
    758 	va_end(ap);
    759 	exit(eval);
    760 }
    761 
    762 void
    763 warn(const char *fmt, ...)
    764 {
    765 	va_list ap;
    766 	va_start(ap, fmt);
    767 	_Vdomessage(1, fmt, ap);
    768 	va_end(ap);
    769 }
    770