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