167754Smsmith/*	$NetBSD: loadbsd.c,v 1.38 2023/05/14 16:13:05 phx Exp $	*/
267754Smsmith
367754Smsmith/*
467754Smsmith * Copyright (c) 1994 Michael L. Hitch
567754Smsmith * All rights reserved.
667754Smsmith *
7217365Sjkim * Redistribution and use in source and binary forms, with or without
8217365Sjkim * modification, are permitted provided that the following conditions
970243Smsmith * are met:
1067754Smsmith * 1. Redistributions of source code must retain the above copyright
11217365Sjkim *    notice, this list of conditions and the following disclaimer.
12217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright
13217365Sjkim *    notice, this list of conditions and the following disclaimer in the
14217365Sjkim *    documentation and/or other materials provided with the distribution.
15217365Sjkim *
16217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17217365Sjkim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18217365Sjkim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19217365Sjkim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20217365Sjkim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21217365Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22217365Sjkim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23217365Sjkim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24217365Sjkim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2567754Smsmith * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26217365Sjkim */
27217365Sjkim
28217365Sjkim#include <errno.h>
2967754Smsmith#include <stdio.h>
30217365Sjkim#include <stdlib.h>
31217365Sjkim#include <string.h>
32217365Sjkim#include <stdarg.h>
33217365Sjkim
34217365Sjkim#include <exec/memory.h>
35217365Sjkim#include <exec/execbase.h>
36217365Sjkim#include <exec/resident.h>
37217365Sjkim#include <graphics/gfxbase.h>
38217365Sjkim#include <libraries/expansion.h>
39217365Sjkim#include <libraries/expansionbase.h>
40217365Sjkim#include <libraries/configregs.h>
41217365Sjkim#include <libraries/configvars.h>
42217365Sjkim#include <proto/expansion.h>
4367754Smsmith#include <proto/graphics.h>
4467754Smsmith#include <proto/exec.h>
4567754Smsmith#include <proto/dos.h>
4667754Smsmith
4767754Smsmith/* Get definitions for boothowto */
4867754Smsmith#include "sys/reboot.h"
4967754Smsmith#include "inttypes.h"
50117521Snjl#include "loadfile.h"
5167754Smsmith
5267754Smsmith#undef AOUT_LDPGSZ
5367754Smsmith#define AOUT_LDPGSZ 8192
5467754Smsmith
55102550Siwasaki#undef sleep
5691116Smsmith#define sleep(n) if (!t_flag) (void)Delay(50*n)
5791116Smsmith
5887031Smsmith/*
5967754Smsmith *	Version history:
6067754Smsmith *	1.x	Kernel startup interface version check.
6187031Smsmith *	2.0	Added symbol table end address and symbol table support.
6267754Smsmith *	2.1	03/23/94 - Round up end of fastram segment.
6367754Smsmith *		Check fastram segment size for minimum of 2M.
6467754Smsmith *		Use largest segment of highest priority if -p option.
65129684Snjl *		Print out fastram size in KB if not a multiple of MB.
66129684Snjl *	2.2	03/24/94 - Zero out all unused registers.
67129684Snjl *		Started version history comment.
68138287Smarks *	2.3	04/26/94 - Added -D option to enter debugger on boot.
69129684Snjl *	2.4	04/30/94 - Cpuid includes base machine type.
70129684Snjl *		Also check if CPU is capable of running NetBSD.
71129684Snjl *	2.5	05/17/94 - Add check for "A3000 bonus".
72129684Snjl *	2.6	06/05/94 - Added -c option to override machine type.
73129684Snjl *	2.7	06/15/94 - Pass E clock frequency.
74129684Snjl *	2.8	06/22/94 - Fix supervisor stack usage.
75117521Snjl *	2.9	06/26/94 - Use PAL flag for E clock freq on pre 2.0 WB
76117521Snjl *		Added AGA enable parameter
77151937Sjkim *	2.10	12/22/94 - Use FindResident() & OpenResource() for machine
78117521Snjl *		type detection.
79151937Sjkim *		Add -n flag & option for non-contiguous memory.
80151937Sjkim *		01/28/95 - Corrected -n on usage & help messages.
81167802Sjkim *	2.11	03/12/95 - Check kernel size against chip memory size.
82117521Snjl *	2.12	11/11/95 - Add -I option to inhibit synchronous transfer
83117521Snjl *		11/12/95 - New kernel startup interface version - to
84167802Sjkim *		support loading kernel image to fastmem rather than chipmem.
85117521Snjl *	2.13	04/15/96 - Direct load to fastmem.
86117521Snjl *		Add -Z flag to force chipmem load.
87117521Snjl *		Moved test mode exit to later - kernel image is created
88117521Snjl *		and startup interface version checked in test mode.
89117521Snjl *		Add -s flag for compatibility to bootblock loader.
9067754Smsmith *		05/02/96 - Add a maximum startup interface version level
9167754Smsmith *		to allow future kernel compatibility.
9267754Smsmith *	2.14	06/26/96 is - Add first version of kludges needed to
9367754Smsmith *		boot on DraCos. This can probably be done a bit more cleanly
9467754Smsmith *		using TTRs, but it works for now.
9567754Smsmith *	2.15	07/28/96 is - Add first version of kludges needed to
9685756Smsmith *		get FusionForty kickrom'd memory back. Hope this doesn't
9767754Smsmith *		break anything else.
98151937Sjkim *	2.16	07/08/00 - Added bootverbose support.
9985756Smsmith *		01/15/03 - Plugged resource leaks.
10067754Smsmith *		Fixed printf() statements.
10167754Smsmith *		Ansified.
102114237Snjl *	3.0	01/16/03 - ELF support through loadfile() interface.
10367754Smsmith *	3.1	07/10/11 - Added a serial console flag
104167802Sjkim *		11/18/15 - (gnikl) Added detection of A600.
10567754Smsmith *		Fix handling of multiple -n options.
106167802Sjkim *	3.2	09/02/22 - Make it compile with modern AmigaOS gcc ports.
10767754Smsmith *	3.3	01/04/22 - Loading the kernel to the highest priority memory
108199337Sjkim *		segment is the default now. New option -l to revert to the
10967754Smsmith *		previous behaviour of largest segment.
110199337Sjkim *		New option -M to define a minimum size for the memory segment.
11167754Smsmith */
112167802Sjkimstatic const char _version[] = "$VER: LoadBSD 3.3 (01.04.2023)";
11367754Smsmith
114167802Sjkim/*
115167802Sjkim * Kernel startup interface version
116167802Sjkim *	1:	first version of loadbsd
117167802Sjkim *	2:	needs esym location passed in a4
118167802Sjkim *	3:	load kernel image into fastmem rather than chipmem
119167802Sjkim *	MAX:	highest version with backward compatibility.
120193267Sjkim */
121167802Sjkim#define KERNEL_STARTUP_VERSION		3
122193267Sjkim#define	KERNEL_STARTUP_VERSION_MAX	9
123193267Sjkim
124209746Sjkim#define DRACOREVISION (*(UBYTE *)0x02000009)
125193267Sjkim#define DRACOMMUMARGIN 0x200000
126228110Sjkim
127209746Sjkim#define MAXMEMSEG	16
128209746Sjkimstruct boot_memlist {
12991116Smsmith	u_int	m_nseg; /* num_mem; */
13091116Smsmith	struct boot_memseg {
13167754Smsmith		u_int	ms_start;
13267754Smsmith		u_int	ms_size;
13367754Smsmith		u_short	ms_attrib;
13467754Smsmith		short	ms_pri;
135151937Sjkim	} m_seg[MAXMEMSEG];
136151937Sjkim};
137114237Snjlstruct boot_memlist memlist;
138114237Snjlstruct boot_memlist *kmemlist;
13967754Smsmith
140114237Snjlvoid err(int eval, const char *, ...);
141114237Snjlint getopt(int, char * const [], const char *);
14267754Smsmithvoid get_mem_config (void **, u_long *, u_long *);
14367754Smsmithvoid get_cpuid (void);
144114237Snjlvoid get_eclock (void);
14567754Smsmithvoid get_AGA (void);
146114237Snjlvoid usage (void);
147114237Snjlvoid verbose_usage (void);
14867754Smsmithextern void startit (void *, u_long, u_long, void *, u_long, u_long, int, void *,
149167802Sjkim		int, int, u_long, u_long, int);
150167802Sjkimextern u_long startit_sz;
151167802Sjkim
152167802Sjkimextern char *optarg;
153167802Sjkimextern int optind;
154167802Sjkim
155167802Sjkimstruct ExpansionBase *ExpansionBase = NULL;
156167802Sjkimstruct GfxBase *GfxBase = NULL;
157167802Sjkim
158167802Sjkimu_int minmemsz = 2 * 1024 * 1024;
159167802Sjkimint p_flag = 1;
16067754Smsmithint k_flag;
16167754Smsmithint t_flag;
162131440Smarksint reqmemsz;
163131440Smarksint S_flag;
164131440Smarksu_long I_flag;
165131440Smarksint Z_flag;
166131440Smarksu_long cpuid;
167114237Snjllong eclock_freq;
16867754Smsmithlong amiga_flags;
16987031Smsmithchar *program_name;
17087031Smsmithu_char *kp;
17199679Siwasakiu_long kpsz;
17287031Smsmith
17377424Smsmith
17467754Smsmithvoid
17599679Siwasakiexit_func(void)
17677424Smsmith{
177100966Siwasaki	if (kp)
178100966Siwasaki		FreeMem(kp, kpsz);
179167802Sjkim	if (ExpansionBase)
180100966Siwasaki		CloseLibrary((struct Library *)ExpansionBase);
18191116Smsmith	if (GfxBase)
18277424Smsmith		CloseLibrary((struct Library *)GfxBase);
18399679Siwasaki}
18499679Siwasaki
18591116Smsmithint
186228110Sjkimmain(int argc, char **argv)
18791116Smsmith{
188107325Siwasaki	struct ConfigDev *cd, *kcd;
189228110Sjkim	u_long fmemsz, cmemsz, ksize, marks[MARK_MAX];
190197104Sjkim	int boothowto, ncd, i, mem_ix, ch;
191107325Siwasaki	u_short kvers;
192197104Sjkim	int *nkcd;
193107325Siwasaki	u_char *fmem;
194197104Sjkim	char *esym;
195197104Sjkim	void (*start_it) (void *, u_long, u_long, void *, u_long, u_long,
196197104Sjkim	     int, void *, int, int, u_long, u_long, int) = startit;
197197104Sjkim	char *kernel_name;
19891116Smsmith
19991116Smsmith	atexit(exit_func);
20091116Smsmith
20191116Smsmith	program_name = argv[0];
20291116Smsmith	boothowto = RB_SINGLE;
20391116Smsmith
204222544Sjkim	if (argc < 2)
205222544Sjkim		usage();
20691116Smsmith
20799679Siwasaki	if ((GfxBase = (void *)OpenLibrary(GRAPHICSNAME, 0)) == NULL)
20899679Siwasaki		err(20, "can't open graphics library");
20991116Smsmith	if ((ExpansionBase=(void *)OpenLibrary(EXPANSIONNAME, 0)) == NULL)
21091116Smsmith		err(20, "can't open expansion library");
21167754Smsmith
21267754Smsmith	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
471void
472get_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 */
620void
621get_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
666void
667get_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
677void
678get_AGA(void)
679{
680	/*
681	 * Determine if an AGA mode is active
682	 */
683}
684
685void
686usage(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
693void
694verbose_usage(void)
695{
696	fprintf(stderr, "\n\
697NAME\n\
698\t%s - loads NetBSD from amiga dos.\n\
699SYNOPSIS\n\
700\t%s [-abhklpstACDSVZ] [-c machine] [-m size] [-M size] [-n mode] [-I sync-inhibit] kernel\n\
701OPTIONS\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\
732HISTORY\n\
733\tThis version supports Kernel version 720 +\n",
734      program_name, program_name);
735      exit(1);
736}
737
738static 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
752void
753err(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
762void
763warn(const char *fmt, ...)
764{
765	va_list ap;
766	va_start(ap, fmt);
767	_Vdomessage(1, fmt, ap);
768	va_end(ap);
769}
770