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