1 /* 2 * $NetBSD: main.c,v 1.23 2007/03/04 05:59:31 christos 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 <lib/libsa/stand.h> 48 49 #include "libstubs.h" 50 #include "samachdep.h" 51 #include "loadfile.h" 52 53 #undef AOUT_LDPGSZ 54 #define AOUT_LDPGSZ 8192 55 #define __PGSZ 8192 56 57 #define DRACOREVISION (*(u_int8_t *)0x02000009) 58 #define DRACOMMUMARGIN 0x200000 59 #define DRACOZ2OFFSET 0x3000000 60 #define DRACOZ2MAX 0x1000000 61 62 #define EXECMIN 36 63 64 /* 65 * vers.c (generated by newvers.sh) 66 */ 67 extern const char bootprog_rev[]; 68 extern const char bootprog_date[]; 69 extern const char bootprog_maker[]; 70 71 void startit(void *, u_long, u_long, void *, u_long, u_long, int, void *, 72 int, int, u_long, u_long, u_long, int); 73 int get_cpuid(u_int32_t *); 74 #ifdef PPCBOOTER 75 u_int16_t kickstart[]; 76 size_t kicksize; 77 #else 78 void startit_end(void); 79 #endif 80 81 /* 82 * Kernel startup interface version 83 * 1: first version of loadbsd 84 * 2: needs esym location passed in a4 85 * 3: load kernel image into fastmem rather than chipmem 86 * MAX: highest version with backward compatibility. 87 */ 88 89 #define KERNEL_STARTUP_VERSION 3 90 #define KERNEL_STARTUP_VERSION_MAX 9 91 92 static long get_number(char **); 93 94 extern char default_command[]; 95 96 int 97 pain(void *aio, void *cons) 98 { 99 char linebuf[128]; 100 char *kernel_name = default_command; 101 char *path = default_command; 102 int boothowto = RB_AUTOBOOT; 103 u_int32_t cpuid = 0; 104 int amiga_flags = 0; 105 u_int32_t I_flag = 0; 106 int k_flag = 0; 107 int p_flag = 0; 108 int m_value = 0; 109 int S_flag = 0; 110 int t_flag = 0; 111 112 u_int32_t fmem = 0x0; 113 int fmemsz = 0x0; 114 int cmemsz = 0x0; 115 int eclock = SysBase->EClockFreq; 116 /* int skip_chipmem = 0; */ 117 118 void (*start_it)(void *, u_long, u_long, void *, u_long, u_long, int, 119 void *, int, int, u_long, u_long, u_long, int); 120 121 void *kp; 122 u_int16_t *kvers; 123 int ksize; 124 void *esym = 0; 125 int32_t *nkcd; 126 struct cfdev *cd, *kcd; 127 struct boot_memseg *kmemseg; 128 struct boot_memseg *memseg; 129 struct MemHead *mh; 130 u_int32_t from, size, vfrom, vsize; 131 int contflag, mapped1to1; 132 133 int ncd, nseg; 134 char c; 135 136 u_long marks[MARK_MAX]; 137 138 extern u_int16_t timelimit; 139 140 extern u_int32_t aio_base; 141 142 xdinit(aio); 143 144 if (consinit(cons)) 145 return(1); 146 147 /* 148 * we need V36 for: EClock, RDB Bootblocks, CacheClearU 149 */ 150 151 if (SysBase->LibNode.Version < EXECMIN) { 152 printf("Exec V%ld, need V%ld\n", 153 (long)SysBase->LibNode.Version, (long)EXECMIN); 154 goto out; 155 } 156 157 /* 158 * XXX Do this differently; default boot will attempt to load a list of 159 * XXX kernels until one of them succeeds. 160 */ 161 timelimit = 3; 162 again: 163 #ifdef PPCBOOTER 164 printf("\nNetBSD/AmigaPPC " NETBSD_VERS " Bootstrap, Revision %s\n", 165 bootprog_rev); 166 #else 167 printf("\nNetBSD/Amiga " NETBSD_VERS " Bootstrap, Revision %s\n", 168 bootprog_rev); 169 #endif 170 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 171 printf("\n"); 172 printf("Boot: [%s] ", kernel_name); 173 174 gets(linebuf); 175 176 if (*linebuf == 'q') 177 return 1; 178 179 if (*linebuf) 180 path = linebuf; 181 182 /* 183 * parse boot command for path name and process any options 184 */ 185 while ((c = *path)) { 186 while (c == ' ') 187 c = *++path; 188 if (c == '-') { 189 while ((c = *++path) && c != ' ') { 190 switch (c) { 191 case 'a': /* multi-user state */ 192 boothowto &= ~RB_SINGLE; 193 break; 194 case 'b': /* ask for root device */ 195 boothowto |= RB_ASKNAME; 196 break; 197 case 'c': /* force machine model */ 198 cpuid = get_number(&path) << 16; 199 break; 200 case 'k': /* Reserve first 4M fastmem */ 201 k_flag++; 202 break; 203 case 'm': /* Force fastmem size */ 204 m_value = get_number(&path) * 1024; 205 break; 206 case 'n': /* non-contiguous memory */ 207 amiga_flags |= 208 (get_number(&path) & 3) << 1; 209 break; 210 case 'p': /* Select fastmem by priority */ 211 p_flag++; 212 break; 213 case 'q': 214 boothowto |= AB_QUIET; 215 break; 216 case 's': /* single-user state */ 217 boothowto |= RB_SINGLE; 218 break; 219 case 't': /* test flag */ 220 t_flag = 1; 221 break; 222 case 'v': 223 boothowto |= AB_VERBOSE; 224 break; 225 case 'A': /* enable AGA modes */ 226 amiga_flags |= 1; 227 break; 228 case 'D': /* enter Debugger */ 229 boothowto |= RB_KDB; 230 break; 231 case 'I': /* inhibit sync negotiation */ 232 I_flag = get_number(&path); 233 break; 234 case 'K': /* remove 1st 4MB fastmem */ 235 break; 236 case 'S': /* include debug symbols */ 237 S_flag = 1; 238 break; 239 } 240 } 241 } else { 242 /* XXX Handle kernel_name differently */ 243 kernel_name = path; 244 while ((c = *++path) && c != ' ') 245 ; 246 if (c) 247 *path++ = 0; 248 } 249 } 250 /* XXX Handle kernel_name differently */ 251 while ((c = *kernel_name) && c == ' ') 252 ++kernel_name; 253 path = kernel_name; 254 while ((c = *path) && c != ' ') 255 ++path; 256 if (c) 257 *path = 0; 258 259 if (get_cpuid(&cpuid)) 260 goto out; 261 262 ExpansionBase = OpenLibrary("expansion.library", 0); 263 if (!ExpansionBase) { 264 printf("can't open %s\n", "expansion.library"); 265 return 1; 266 } 267 268 for (ncd=0, cd=0; (cd = FindConfigDev(cd, -1, -1)); ncd++) 269 /* nothing */; 270 271 /* find memory list */ 272 273 memseg = (struct boot_memseg *)alloc(16*sizeof(struct boot_memseg)); 274 275 /* Forbid(); */ 276 277 nseg = 0; 278 mh = SysBase->MemLst; 279 vfrom = mh->Lower & -__PGSZ; 280 vsize = (mh->Upper & -__PGSZ) - vfrom; 281 contflag = mapped1to1 = 0; 282 283 do { 284 size = vsize; 285 286 if (SysBase->LibNode.Version > 36) { 287 from = CachePreDMA(vfrom, &size, contflag); 288 contflag = DMAF_Continue; 289 mapped1to1 = (from == vfrom); 290 vsize -= size; 291 vfrom += size; 292 } else { 293 from = vfrom; 294 mapped1to1 = 1; 295 vsize = 0; 296 } 297 298 #ifdef DEBUG_MEMORY_LIST 299 printf("%lx %lx %lx %ld/%lx %lx\n", 300 (long)from, (long)size, 301 (long)mh->Attribs, (long)mh->Pri, 302 (long)vfrom, (long)vsize); 303 #endif 304 /* Insert The Evergrowing Kludge List Here: */ 305 306 /* a) dont load kernel over DraCo MMU table */ 307 308 if (((cpuid >> 24) == 0x7D) && 309 ((from & -DRACOMMUMARGIN) == 0x40000000) && 310 (size >= DRACOMMUMARGIN)) { 311 312 memseg[nseg].ms_start = from & -DRACOMMUMARGIN; 313 memseg[nseg].ms_size = DRACOMMUMARGIN; 314 memseg[nseg].ms_attrib = mh->Attribs; 315 memseg[nseg].ms_pri = mh->Pri; 316 317 size -= DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 318 from += DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 319 ++nseg; 320 } 321 322 if ((mh->Attribs & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) { 323 size += from; 324 cmemsz = size; 325 from = 0; 326 } else if ((fmemsz < size) && mapped1to1) { 327 fmem = from; 328 fmemsz = size; 329 } 330 331 memseg[nseg].ms_start = from; 332 memseg[nseg].ms_size = size; 333 memseg[nseg].ms_attrib = mh->Attribs; 334 memseg[nseg].ms_pri = mh->Pri; 335 336 if (vsize == 0) { 337 mh = mh->next; 338 contflag = 0; 339 if (mh->next) { 340 vfrom = mh->Lower & -__PGSZ; 341 vsize = (mh->Upper & -__PGSZ) - vfrom; 342 } 343 } 344 } while ((++nseg <= 16) && vsize); 345 346 /* Permit(); */ 347 348 if (k_flag) { 349 fmem += 4*1024*1024; 350 fmemsz -= 4*1024*1024; 351 } 352 if (m_value && m_value < fmemsz) 353 fmemsz = m_value; 354 355 /* XXX Loop through list of kernels */ 356 printf("Loading %s: ", kernel_name); 357 /* 358 * XXX Call loadfile with COUNT* options to get size 359 * XXX Allocate memory for kernel + additional data 360 * XXX Call loadfile with LOAD* options to load text/data/symbols 361 */ 362 marks[MARK_START] = 0; 363 if (loadfile(kernel_name, marks, 364 COUNT_TEXT|COUNT_TEXTA|COUNT_DATA|COUNT_BSS | 365 (S_flag ? (COUNT_SYM|COUNT_HDR) : 0)) == -1) { 366 goto err; 367 } 368 ksize = ((marks[MARK_END] + 3) & ~3) 369 + sizeof(*nkcd) + ncd*sizeof(*cd) 370 + sizeof(*nkcd) + nseg * sizeof(struct boot_memseg); 371 372 #ifdef PPCBOOTER 373 kp = alloc(ksize); 374 #else 375 kp = alloc(ksize + 256 + ((u_char *)startit_end - (u_char *)startit)); 376 #endif 377 if (kp == 0) { 378 errno = ENOMEM; 379 goto err; 380 } 381 382 marks[MARK_START] = (u_long)kp; 383 if (loadfile(kernel_name, marks, 384 LOAD_TEXT|LOAD_TEXTA|LOAD_DATA|LOAD_BSS| 385 (S_flag ? (LOAD_SYM|LOAD_HDR) : 0)) == -1) { 386 printf("Kernel load failed\n"); 387 goto err; 388 } 389 marks[MARK_END] = (marks[MARK_END] + 3) & ~3; 390 nkcd = (int *)marks[MARK_END]; 391 if (S_flag) 392 esym = (void*)(marks[MARK_END] - marks[MARK_START]); 393 /* #ifndef PPCBOOTER*/ 394 kvers = (u_short *)(marks[MARK_ENTRY] - 2); 395 396 if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73) { 397 printf("\nnewer bootblock required: %ld\n", (long)*kvers); 398 goto freeall; 399 } 400 if (*kvers < KERNEL_STARTUP_VERSION || *kvers == 0x4e73) { 401 printf("\nkernel too old for bootblock\n"); 402 goto freeall; 403 } 404 #if 0 405 if (*kvers > KERNEL_STARTUP_VERSION) 406 printf("\nKernel V%ld newer than bootblock V%ld\n", 407 (long)*kvers, (long)KERNEL_STARTUP_VERSION); 408 #endif 409 if (marks[MARK_NSYM] && (*kvers == 0x4e73 || *kvers <= 1)) { 410 nkcd = (int *)marks[MARK_SYM]; 411 esym = 0; 412 printf("Supressing %ld kernel symbols\n", marks[MARK_NSYM]); 413 timelimit = 60; 414 (void)getchar(); 415 } 416 /* version checks */ 417 putchar('\n'); 418 419 *nkcd = ncd; 420 kcd = (struct cfdev *)(nkcd + 1); 421 422 while ((cd = FindConfigDev(cd, -1, -1))) { 423 *kcd = *cd; 424 #ifndef PPCBOOTER 425 if (((cpuid >> 24) == 0x7D) && 426 ((u_long)kcd->addr < 0x1000000)) { 427 kcd->addr += 0x3000000; 428 } 429 #endif 430 ++kcd; 431 } 432 433 nkcd = (int32_t *)kcd; 434 *nkcd = nseg; 435 436 kmemseg = (struct boot_memseg *)(nkcd + 1); 437 438 while (nseg-- > 0) 439 *kmemseg++ = *memseg++; 440 441 #ifdef PPCBOOTER 442 /* 443 * we use the ppc starter... 444 */ 445 start_it = startit; 446 #else 447 /* 448 * Copy startup code to end of kernel image and set start_it. 449 */ 450 memcpy(kp + ksize + 256, (char *)startit, 451 (char *)startit_end - (char *)startit); 452 CacheClearU(); 453 start_it = (void *)(kp + ksize + 256); 454 #endif 455 printf("*** Loading from %08lx to Fastmem %08lx ***\n", 456 (u_long)kp, (u_long)fmem); 457 /* sleep(2); */ 458 459 #if 0 460 printf("would start(kp=0x%lx, ksize=%ld, entry=0x%lx,\n" 461 "fmem=0x%lx, fmemsz=%ld, cmemsz=%ld\n" 462 "boothow=0x%lx, esym=0x%lx, cpuid=0x%lx, eclock=%ld\n" 463 "amigaflags=0x%lx, I_flags=0x%lx, ok?\n", 464 (u_long)kp, (u_long)ksize, marks[MARK_ENTRY] - marks[MARK_START], 465 (u_long)fmem, (u_long)fmemsz, (u_long)cmemsz, 466 (u_long)boothowto, (u_long)esym, (u_long)cpuid, (u_long)eclock, 467 (u_long)amiga_flags, (u_long)I_flag); 468 timelimit = 60; 469 (void)getchar(); 470 #endif 471 #ifdef DEBUG_MEMORY_LIST 472 timelimit = 0; 473 #else 474 timelimit = 2; 475 #endif 476 (void)getchar(); 477 478 #ifdef PPCBOOTER 479 startit 480 #else 481 start_it 482 #endif 483 (kp, ksize, marks[MARK_ENTRY] - marks[MARK_START], (void *)fmem, fmemsz, cmemsz, 484 boothowto, esym, cpuid, eclock, amiga_flags, I_flag, 485 aio_base >> 9, 1); 486 /*NOTREACHED*/ 487 488 freeall: 489 dealloc(kp, ksize); 490 err: 491 printf("\nError %ld\n", (long)errno); 492 goto again; 493 out: 494 timelimit = 10; 495 (void)getchar(); 496 return 1; 497 } 498 499 static 500 long get_number(char **ptr) 501 { 502 long value = 0; 503 int base = 10; 504 char *p = *ptr; 505 char c; 506 char sign = 0; 507 508 c = *++p; 509 while (c == ' ') 510 c = *++p; 511 if (c == '-') { 512 sign = -1; 513 c = *++p; 514 } 515 if (c == '$') { 516 base = 16; 517 c = *++p; 518 } else if (c == '0') { 519 c = *++p; 520 if ((c & 0xdf) == 'X') { 521 base = 16; 522 c = *++p; 523 } 524 } 525 while (c) { 526 if (c >= '0' && c <= '9') 527 c -= '0'; 528 else { 529 c = (c & 0xdf) - 'A' + 10; 530 if (base != 16 || c < 10 || c > 15) 531 break; 532 } 533 value = value * base + c; 534 c = *++p; 535 } 536 *ptr = p - 1; 537 #ifdef TEST 538 fprintf(stderr, "get_number: got %c0x%x", 539 sign ? '-' : '+', value); 540 #endif 541 return (sign ? -value : value); 542 } 543 544 /* 545 * Try to determine the machine ID by searching the resident module list 546 * for modules only present on specific machines. (Thanks, Bill!) 547 */ 548 549 int 550 get_cpuid(u_int32_t *cpuid) 551 { 552 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */ 553 if (*cpuid & 0xffff0000) { 554 if ((*cpuid >> 24) == 0x7D) 555 return 0; 556 557 switch (*cpuid >> 16) { 558 case 500: 559 case 600: 560 case 1000: 561 case 1200: 562 case 2000: 563 case 3000: 564 case 4000: 565 return 0; 566 default: 567 printf("Amiga %ld ???\n", 568 (long)(*cpuid >> 16)); 569 return(1); 570 } 571 } 572 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus") 573 || FindResident("A1000 Bonus")) 574 *cpuid |= 4000 << 16; 575 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus") 576 || (SysBase->LibNode.Version == 36)) 577 *cpuid |= 3000 << 16; 578 else if (OpenResource("card.resource")) { 579 /* Test for AGA? */ 580 *cpuid |= 1200 << 16; 581 } else if (OpenResource("draco.resource")) { 582 *cpuid |= (32000 | DRACOREVISION) << 16; 583 } 584 /* 585 * Nothing found, it's probably an A2000 or A500 586 */ 587 if ((*cpuid >> 16) == 0) 588 *cpuid |= 2000 << 16; 589 590 return 0; 591 } 592