xref: /netbsd-src/sys/arch/amiga/stand/loadbsd/loadbsd.c (revision 34815acdf9c90502e94f6be3fe88e54bed7bf395)
1 /*	$NetBSD: loadbsd.c,v 1.38 2023/05/14 16:13:05 phx 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
exit_func(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
main(int argc,char ** argv)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
get_mem_config(void ** fmem,u_long * fmemsz,u_long * cmemsz)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
get_cpuid(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
get_eclock(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
get_AGA(void)678 get_AGA(void)
679 {
680 	/*
681 	 * Determine if an AGA mode is active
682 	 */
683 }
684 
685 void
usage(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
verbose_usage(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
_Vdomessage(int doerrno,const char * fmt,va_list args)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
err(int eval,const char * fmt,...)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
warn(const char * fmt,...)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