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