1 /* 2 * $NetBSD: main.c,v 1.12 2000/09/24 20:56:04 jdolecek Exp $ 3 * 4 * 5 * Copyright (c) 1996,1999 Ignatios Souvatzis 6 * Copyright (c) 1994 Michael L. Hitch 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Michael L. Hitch. 20 * 4. The name of the authors may not be used to endorse or promote products 21 * derived from this software without specific prior written permission 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/cdefs.h> 37 #include <sys/reboot.h> 38 #include <sys/types.h> 39 40 #include <sys/exec_aout.h> 41 42 #include <amiga/cfdev.h> 43 #include <amiga/memlist.h> 44 #include <include/cpu.h> 45 46 #include <saerrno.h> 47 #include <stand.h> 48 49 #include "libstubs.h" 50 #include "samachdep.h" 51 52 #undef __LDPGSZ 53 #define __LDPGSZ 8192 54 #define __PGSZ 8192 55 56 #define DRACOREVISION (*(u_int8_t *)0x02000009) 57 #define DRACOMMUMARGIN 0x200000 58 #define DRACOZ2OFFSET 0x3000000 59 #define DRACOZ2MAX 0x1000000 60 61 #define EXECMIN 36 62 63 void startit __P((void *, u_long, u_long, void *, u_long, u_long, int, void *, 64 int, int, u_long, u_long, u_long, int)); 65 int get_cpuid __P((u_int32_t *)); 66 #ifdef PPCBOOTER 67 u_int16_t kickstart[]; 68 size_t kicksize; 69 #else 70 void startit_end __P((void)); 71 #endif 72 73 /* 74 * Kernel startup interface version 75 * 1: first version of loadbsd 76 * 2: needs esym location passed in a4 77 * 3: load kernel image into fastmem rather than chipmem 78 * MAX: highest version with backward compatibility. 79 */ 80 81 #define KERNEL_STARTUP_VERSION 3 82 #define KERNEL_STARTUP_VERSION_MAX 9 83 84 static long get_number(char **); 85 86 #define VERSION "2.2" 87 88 char default_command[] = "netbsd -ASn2"; 89 90 int 91 pain(aio) 92 void *aio; 93 { 94 long int io = 0; 95 char linebuf[128]; 96 char *kernel_name = default_command; 97 char *path = default_command; 98 int boothowto = RB_AUTOBOOT; 99 u_int32_t cpuid = 0; 100 int amiga_flags = 0; 101 u_int32_t I_flag = 0; 102 int k_flag = 0; 103 int p_flag = 0; 104 int m_value = 0; 105 int S_flag = 0; 106 int t_flag = 0; 107 long stringsz; 108 109 u_int32_t fmem = 0x0; 110 int fmemsz = 0x0; 111 int cmemsz = 0x0; 112 int eclock = SysBase->EClockFreq; 113 /* int skip_chipmem = 0; */ 114 115 void (*start_it)(void *, u_long, u_long, void *, u_long, u_long, int, 116 void *, int, int, u_long, u_long, u_long, int); 117 118 caddr_t kp; 119 u_int16_t *kvers; 120 struct exec ehs; 121 int textsz, ksize; 122 void *esym = 0; 123 int32_t *nkcd; 124 struct cfdev *cd, *kcd; 125 struct boot_memseg *kmemseg; 126 struct boot_memseg *memseg; 127 struct MemHead *mh; 128 u_int32_t from, size, vfrom, vsize; 129 int contflag, mapped1to1; 130 131 int ncd, nseg; 132 char c; 133 134 extern u_int16_t timelimit; 135 136 extern u_int32_t aio_base; 137 138 xdinit(aio); 139 140 if (consinit()) 141 return(1); 142 143 /* 144 * we need V36 for: EClock, RDB Bootblocks, CacheClearU 145 */ 146 147 if (SysBase->LibNode.Version < EXECMIN) { 148 printf("Exec V%ld, need V%ld\n", 149 (long)SysBase->LibNode.Version, (long)EXECMIN); 150 goto out; 151 } 152 153 #ifdef PPCBOOTER 154 printf("\2337mNetBSD/AmigaPPC bootblock " VERSION "\2330m\n%s :- ", 155 kernel_name); 156 #else 157 printf("\2337mNetBSD/Amiga bootblock " VERSION "\2330m\n%s :- ", 158 kernel_name); 159 #endif 160 161 timelimit = 3; 162 gets(linebuf); 163 164 if (*linebuf == 'q') 165 return 1; 166 167 if (*linebuf) 168 path = linebuf; 169 170 /* 171 * parse boot command for path name and process any options 172 */ 173 while ((c = *path)) { 174 while (c == ' ') 175 c = *++path; 176 if (c == '-') { 177 while ((c = *++path) && c != ' ') { 178 switch (c) { 179 case 'a': /* multi-user state */ 180 boothowto &= ~RB_SINGLE; 181 break; 182 case 'b': /* ask for root device */ 183 boothowto |= RB_ASKNAME; 184 break; 185 case 'c': /* force machine model */ 186 cpuid = get_number(&path) << 16; 187 break; 188 case 'k': /* Reserve first 4M fastmem */ 189 k_flag++; 190 break; 191 case 'm': /* Force fastmem size */ 192 m_value = get_number(&path) * 1024; 193 break; 194 case 'n': /* non-contiguous memory */ 195 amiga_flags |= 196 (get_number(&path) & 3) << 1; 197 break; 198 case 'p': /* Select fastmem by priority */ 199 p_flag++; 200 break; 201 case 'q': 202 boothowto |= AB_QUIET; 203 break; 204 case 's': /* single-user state */ 205 boothowto |= RB_SINGLE; 206 break; 207 case 't': /* test flag */ 208 t_flag = 1; 209 break; 210 case 'v': 211 boothowto |= AB_VERBOSE; 212 break; 213 case 'A': /* enable AGA modes */ 214 amiga_flags |= 1; 215 break; 216 case 'D': /* enter Debugger */ 217 boothowto |= RB_KDB; 218 break; 219 case 'I': /* inhibit sync negotiation */ 220 I_flag = get_number(&path); 221 break; 222 case 'K': /* remove 1st 4MB fastmem */ 223 break; 224 case 'S': /* include debug symbols */ 225 S_flag = 1; 226 break; 227 } 228 } 229 } else { 230 kernel_name = path; 231 while ((c = *++path) && c != ' ') 232 ; 233 if (c) 234 *path++ = 0; 235 } 236 } 237 while ((c = *kernel_name) && c == ' ') 238 ++kernel_name; 239 path = kernel_name; 240 while ((c = *path) && c != ' ') 241 ++path; 242 if (c) 243 *path = 0; 244 245 if (get_cpuid(&cpuid)) 246 goto out; 247 248 ExpansionBase = OpenLibrary("expansion.library", 0); 249 if (!ExpansionBase) { 250 printf("can't open %s\n", "expansion.library"); 251 return 1; 252 } 253 254 for (ncd=0, cd=0; (cd = FindConfigDev(cd, -1, -1)); ncd++) 255 /* nothing */; 256 257 /* find memory list */ 258 259 memseg = (struct boot_memseg *)alloc(16*sizeof(struct boot_memseg)); 260 261 /* Forbid(); */ 262 263 nseg = 0; 264 mh = SysBase->MemLst; 265 vfrom = mh->Lower & -__PGSZ; 266 vsize = (mh->Upper & -__PGSZ) - vfrom; 267 contflag = mapped1to1 = 0; 268 269 do { 270 size = vsize; 271 272 if (SysBase->LibNode.Version > 36) { 273 from = CachePreDMA(vfrom, &size, contflag); 274 contflag = DMAF_Continue; 275 mapped1to1 = (from == vfrom); 276 vsize -= size; 277 vfrom += size; 278 } else { 279 from = vfrom; 280 mapped1to1 = 1; 281 vsize = 0; 282 } 283 284 #ifdef DEBUG_MEMORY_LIST 285 printf("%lx %lx %lx %ld/%lx %lx\n", 286 (long)from, (long)size, 287 (long)mh->Attribs, (long)mh->Pri, 288 (long)vfrom, (long)vsize); 289 #endif 290 /* Insert The Evergrowing Kludge List Here: */ 291 292 /* a) dont load kernel over DraCo MMU table */ 293 294 if (((cpuid >> 24) == 0x7D) && 295 ((from & -DRACOMMUMARGIN) == 0x40000000) && 296 (size >= DRACOMMUMARGIN)) { 297 298 memseg[nseg].ms_start = from & -DRACOMMUMARGIN; 299 memseg[nseg].ms_size = DRACOMMUMARGIN; 300 memseg[nseg].ms_attrib = mh->Attribs; 301 memseg[nseg].ms_pri = mh->Pri; 302 303 size -= DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 304 from += DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 305 ++nseg; 306 } 307 308 if ((mh->Attribs & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) { 309 size += from; 310 cmemsz = size;; 311 from = 0; 312 } else if ((fmemsz < size) && mapped1to1) { 313 fmem = from; 314 fmemsz = size; 315 } 316 317 memseg[nseg].ms_start = from; 318 memseg[nseg].ms_size = size; 319 memseg[nseg].ms_attrib = mh->Attribs; 320 memseg[nseg].ms_pri = mh->Pri; 321 322 if (vsize == 0) { 323 mh = mh->next; 324 contflag = 0; 325 if (mh->next) { 326 vfrom = mh->Lower & -__PGSZ; 327 vsize = (mh->Upper & -__PGSZ) - vfrom; 328 } 329 } 330 } while ((++nseg <= 16) && vsize); 331 332 /* Permit(); */ 333 334 if (k_flag) { 335 fmem += 4*1024*1024; 336 fmemsz -= 4*1024*1024; 337 } 338 if (m_value && m_value < fmemsz) 339 fmemsz = m_value; 340 341 printf("Loading %s: ", kernel_name); 342 io = open(kernel_name, 0); 343 if (io < 0) 344 goto err; 345 346 if (read(io, &ehs, sizeof(ehs)) != sizeof(ehs)) { 347 errno = ENOEXEC; 348 goto err; 349 } 350 351 #ifdef PPCBOOTER 352 /* XXX to be done */ 353 #else 354 if ((N_GETMAGIC(ehs) != NMAGIC) || (N_GETMID(ehs) != MID_M68K)) { 355 errno = ENOEXEC; 356 goto err; 357 } 358 #endif 359 360 textsz = (ehs.a_text + __LDPGSZ - 1) & (-__LDPGSZ); 361 esym = 0; 362 363 ksize = textsz + ehs.a_data + ehs.a_bss 364 + sizeof(*nkcd) + ncd*sizeof(*cd) 365 + sizeof(*nkcd) + nseg * sizeof(struct boot_memseg); 366 367 if (S_flag && ehs.a_syms) { 368 if (lseek(io, ehs.a_text+ ehs.a_data+ ehs.a_syms, SEEK_CUR) 369 <= 0 370 || read(io, &stringsz, 4) != 4 371 || lseek(io, sizeof(ehs), SEEK_SET) < 0) 372 goto err; 373 ksize += ehs.a_syms + 4 + ((stringsz + 3) & ~3); 374 } 375 #ifdef PPCBOOTER 376 kp = alloc(ksize); 377 #else 378 kp = alloc(ksize + 256 + ((u_char *)startit_end - (u_char *)startit)); 379 #endif 380 if (kp == 0) { 381 errno = ENOMEM; 382 goto err; 383 } 384 385 printf("%ld", ehs.a_text); 386 if (ehs.a_text && (read(io, kp, ehs.a_text) != ehs.a_text)) 387 goto err; 388 389 printf("+%ld", ehs.a_data); 390 if (ehs.a_data && (read(io, kp + textsz, ehs.a_data) != ehs.a_data)) 391 goto err; 392 393 printf("+%ld", ehs.a_bss); 394 395 nkcd = (int *)(kp + textsz + ehs.a_data + ehs.a_bss); 396 #ifndef PPCBOOTER 397 kvers = (u_short *)(kp + ehs.a_entry - 2); 398 399 if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73) { 400 printf("\nnewer bootblock required: %ld\n", (long)*kvers); 401 goto freeall; 402 } 403 if (*kvers < KERNEL_STARTUP_VERSION || *kvers == 0x4e73) { 404 printf("\nkernel too old for bootblock\n"); 405 goto freeall; 406 } 407 #if 0 408 if (*kvers > KERNEL_STARTUP_VERSION) 409 printf("\nKernel V%ld newer than bootblock V%ld\n", 410 (long)*kvers, (long)KERNEL_STARTUP_VERSION); 411 #endif 412 if (*kvers != 0x4e73 && *kvers > 1 && S_flag && ehs.a_syms) { 413 *nkcd++ = ehs.a_syms; 414 printf("+[%ld", ehs.a_syms); 415 if (read(io, (char *)nkcd, ehs.a_syms) != ehs.a_syms) 416 goto err; 417 nkcd = (int *)((char *)nkcd + ehs.a_syms); 418 printf("+%ld]", stringsz); 419 if (read(io, (char *)nkcd, stringsz) != stringsz) 420 goto err; 421 nkcd = (int*)((char *)nkcd + ((stringsz + 3) & ~3)); 422 esym = (char *)(textsz + ehs.a_data + ehs.a_bss 423 + ehs.a_syms + 4 + ((stringsz + 3) & ~3)); 424 } 425 #endif 426 putchar('\n'); 427 428 *nkcd = ncd; 429 kcd = (struct cfdev *)(nkcd + 1); 430 431 while ((cd = FindConfigDev(cd, -1, -1))) { 432 *kcd = *cd; 433 #ifndef PPCBOOTER 434 if (((cpuid >> 24) == 0x7D) && 435 ((u_long)kcd->addr < 0x1000000)) { 436 kcd->addr += 0x3000000; 437 } 438 #endif 439 ++kcd; 440 } 441 442 nkcd = (u_int32_t *)kcd; 443 *nkcd = nseg; 444 445 kmemseg = (struct boot_memseg *)(nkcd + 1); 446 447 while (nseg-- > 0) 448 *kmemseg++ = *memseg++; 449 450 #ifdef PPCBOOTER 451 /* 452 * we use the ppc starter... 453 */ 454 start_it = startit; 455 #else 456 /* 457 * Copy startup code to end of kernel image and set start_it. 458 */ 459 memcpy(kp + ksize + 256, (char *)startit, 460 (char *)startit_end - (char *)startit); 461 CacheClearU(); 462 (caddr_t)start_it = kp + ksize + 256; 463 #endif 464 printf("*** Loading from %08lx to Fastmem %08lx ***\n", 465 (u_long)kp, (u_long)fmem); 466 /* sleep(2); */ 467 468 #if 0 469 printf("would start(kp=0x%lx, ksize=%ld, entry=0x%lx,\n" 470 "fmem=0x%lx, fmemsz=%ld, cmemsz=%ld\n" 471 "boothow=0x%lx, esym=0x%lx, cpuid=0x%lx, eclock=%ld\n" 472 "amigaflags=0x%lx, I_flags=0x%lx, ok?\n", 473 (u_long)kp, (u_long)ksize, ehs.a_entry, 474 (u_long)fmem, (u_long)fmemsz, (u_long)cmemsz, 475 (u_long)boothowto, (u_long)esym, (u_long)cpuid, (u_long)eclock, 476 (u_long)amiga_flags, (u_long)I_flag); 477 #endif 478 #ifdef DEBUG_MEMORY_LIST 479 timelimit = 0; 480 #else 481 timelimit = 2; 482 #endif 483 (void)getchar(); 484 485 #ifdef PPCBOOTER 486 startit 487 #else 488 start_it 489 #endif 490 (kp, ksize, ehs.a_entry, (void *)fmem, fmemsz, cmemsz, 491 boothowto, esym, cpuid, eclock, amiga_flags, I_flag, 492 aio_base >> 9, 1); 493 /*NOTREACHED*/ 494 495 freeall: 496 free(kp, ksize); 497 err: 498 printf("\nError %ld\n", (long)errno); 499 close(io); 500 out: 501 timelimit = 10; 502 (void)getchar(); 503 return 1; 504 } 505 506 static 507 long get_number(ptr) 508 char **ptr; 509 { 510 long value = 0; 511 int base = 10; 512 char *p = *ptr; 513 char c; 514 char sign = 0; 515 516 c = *++p; 517 while (c == ' ') 518 c = *++p; 519 if (c == '-') { 520 sign = -1; 521 c = *++p; 522 } 523 if (c == '$') { 524 base = 16; 525 c = *++p; 526 } else if (c == '0') { 527 c = *++p; 528 if ((c & 0xdf) == 'X') { 529 base = 16; 530 c = *++p; 531 } 532 } 533 while (c) { 534 if (c >= '0' && c <= '9') 535 c -= '0'; 536 else { 537 c = (c & 0xdf) - 'A' + 10; 538 if (base != 16 || c < 10 || c > 15) 539 break; 540 } 541 value = value * base + c; 542 c = *++p; 543 } 544 *ptr = p - 1; 545 #ifdef TEST 546 fprintf(stderr, "get_number: got %c0x%x", 547 sign ? '-' : '+', value); 548 #endif 549 return (sign ? -value : value); 550 } 551 552 /* 553 * Try to determine the machine ID by searching the resident module list 554 * for modules only present on specific machines. (Thanks, Bill!) 555 */ 556 557 int 558 get_cpuid(cpuid) 559 u_int32_t *cpuid; 560 { 561 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */ 562 if (*cpuid & 0xffff0000) { 563 if ((*cpuid >> 24) == 0x7D) 564 return 0; 565 566 switch (*cpuid >> 16) { 567 case 500: 568 case 600: 569 case 1000: 570 case 1200: 571 case 2000: 572 case 3000: 573 case 4000: 574 return 0; 575 default: 576 printf("Amiga %ld ???\n", 577 (long)(*cpuid >> 16)); 578 return(1); 579 } 580 } 581 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus") 582 || FindResident("A1000 Bonus")) 583 *cpuid |= 4000 << 16; 584 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus") 585 || (SysBase->LibNode.Version == 36)) 586 *cpuid |= 3000 << 16; 587 else if (OpenResource("card.resource")) { 588 /* Test for AGA? */ 589 *cpuid |= 1200 << 16; 590 } else if (OpenResource("draco.resource")) { 591 *cpuid |= (32000 | DRACOREVISION) << 16; 592 } 593 /* 594 * Nothing found, it's probably an A2000 or A500 595 */ 596 if ((*cpuid >> 16) == 0) 597 *cpuid |= 2000 << 16; 598 599 return 0; 600 } 601