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