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