1 /* 2 * $NetBSD: main.c,v 1.29 2014/03/29 12:49:15 mlelstv 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 'C': /* Serial Console */ 221 amiga_flags |= (1 << 3); 222 break; 223 case 'D': /* enter Debugger */ 224 boothowto |= RB_KDB; 225 break; 226 case 'I': /* inhibit sync negotiation */ 227 I_flag = get_number(&path); 228 break; 229 case 'K': /* remove 1st 4MB fastmem */ 230 break; 231 case 'S': /* include debug symbols */ 232 S_flag = 1; 233 break; 234 } 235 } 236 } else { 237 /* XXX Handle kernel_name differently */ 238 kernel_name = path; 239 while ((c = *++path) && c != ' ') 240 ; 241 if (c) 242 *path++ = 0; 243 } 244 } 245 /* XXX Handle kernel_name differently */ 246 while ((c = *kernel_name) && c == ' ') 247 ++kernel_name; 248 path = kernel_name; 249 while ((c = *path) && c != ' ') 250 ++path; 251 if (c) 252 *path = 0; 253 254 if (get_cpuid(&cpuid)) 255 goto out; 256 257 ExpansionBase = OpenLibrary("expansion.library", 0); 258 if (!ExpansionBase) { 259 printf("can't open %s\n", "expansion.library"); 260 return 1; 261 } 262 263 for (ncd=0, cd=0; (cd = FindConfigDev(cd, -1, -1)); ncd++) 264 /* nothing */; 265 266 /* find memory list */ 267 268 memseg = (struct boot_memseg *)alloc(16*sizeof(struct boot_memseg)); 269 270 /* Forbid(); */ 271 272 nseg = 0; 273 mh = SysBase->MemLst; 274 vfrom = mh->Lower & -__PGSZ; 275 vsize = (mh->Upper & -__PGSZ) - vfrom; 276 contflag = mapped1to1 = 0; 277 278 do { 279 size = vsize; 280 281 if (SysBase->LibNode.Version > 36) { 282 from = CachePreDMA(vfrom, &size, contflag); 283 contflag = DMAF_Continue; 284 mapped1to1 = (from == vfrom); 285 vsize -= size; 286 vfrom += size; 287 } else { 288 from = vfrom; 289 mapped1to1 = 1; 290 vsize = 0; 291 } 292 293 #ifdef DEBUG_MEMORY_LIST 294 printf("%lx %lx %lx %ld/%lx %lx\n", 295 (long)from, (long)size, 296 (long)mh->Attribs, (long)mh->Pri, 297 (long)vfrom, (long)vsize); 298 #endif 299 /* Insert The Evergrowing Kludge List Here: */ 300 301 /* a) dont load kernel over DraCo MMU table */ 302 303 if (((cpuid >> 24) == 0x7D) && 304 ((from & -DRACOMMUMARGIN) == 0x40000000) && 305 (size >= DRACOMMUMARGIN)) { 306 307 memseg[nseg].ms_start = from & -DRACOMMUMARGIN; 308 memseg[nseg].ms_size = DRACOMMUMARGIN; 309 memseg[nseg].ms_attrib = mh->Attribs; 310 memseg[nseg].ms_pri = mh->Pri; 311 312 size -= DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 313 from += DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 314 ++nseg; 315 } 316 317 if ((mh->Attribs & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) { 318 size += from; 319 cmemsz = size; 320 from = 0; 321 } else if ((fmemsz < size) && mapped1to1) { 322 fmem = from; 323 fmemsz = size; 324 } 325 326 memseg[nseg].ms_start = from; 327 memseg[nseg].ms_size = size; 328 memseg[nseg].ms_attrib = mh->Attribs; 329 memseg[nseg].ms_pri = mh->Pri; 330 331 if (vsize == 0) { 332 mh = mh->next; 333 contflag = 0; 334 if (mh->next) { 335 vfrom = mh->Lower & -__PGSZ; 336 vsize = (mh->Upper & -__PGSZ) - vfrom; 337 } 338 } 339 } while ((++nseg <= 16) && vsize); 340 341 /* Permit(); */ 342 343 if (k_flag) { 344 fmem += 4*1024*1024; 345 fmemsz -= 4*1024*1024; 346 } 347 if (m_value && m_value < fmemsz) 348 fmemsz = m_value; 349 350 /* XXX Loop through list of kernels */ 351 printf("Loading %s: ", kernel_name); 352 /* 353 * XXX Call loadfile with COUNT* options to get size 354 * XXX Allocate memory for kernel + additional data 355 * XXX Call loadfile with LOAD* options to load text/data/symbols 356 */ 357 marks[MARK_START] = 0; 358 if (loadfile(kernel_name, marks, 359 COUNT_TEXT|COUNT_TEXTA|COUNT_DATA|COUNT_BSS | 360 (S_flag ? (COUNT_SYM|COUNT_HDR) : 0)) == -1) { 361 goto err; 362 } 363 ksize = ((marks[MARK_END] + 3) & ~3) 364 + sizeof(*nkcd) + ncd*sizeof(*cd) 365 + sizeof(*nkcd) + nseg * sizeof(struct boot_memseg); 366 367 #ifdef PPCBOOTER 368 kp = alloc(ksize); 369 #else 370 kp = alloc(ksize + 256 + ((u_char *)startit_end - (u_char *)startit)); 371 #endif 372 if (kp == 0) { 373 errno = ENOMEM; 374 goto err; 375 } 376 377 marks[MARK_START] = (u_long)kp; 378 if (loadfile(kernel_name, marks, 379 LOAD_TEXT|LOAD_TEXTA|LOAD_DATA|LOAD_BSS| 380 (S_flag ? (LOAD_SYM|LOAD_HDR) : 0)) == -1) { 381 printf("Kernel load failed\n"); 382 goto err; 383 } 384 marks[MARK_END] = (marks[MARK_END] + 3) & ~3; 385 nkcd = (int *)marks[MARK_END]; 386 if (S_flag) 387 esym = (void*)(marks[MARK_END] - marks[MARK_START]); 388 /* #ifndef PPCBOOTER*/ 389 kvers = (u_short *)(marks[MARK_ENTRY] - 2); 390 391 if (*kvers > KERNEL_STARTUP_VERSION_MAX && *kvers != 0x4e73) { 392 printf("\nnewer bootblock required: %ld\n", (long)*kvers); 393 goto freeall; 394 } 395 if (*kvers < KERNEL_STARTUP_VERSION || *kvers == 0x4e73) { 396 printf("\nkernel too old for bootblock\n"); 397 goto freeall; 398 } 399 #if 0 400 if (*kvers > KERNEL_STARTUP_VERSION) 401 printf("\nKernel V%ld newer than bootblock V%ld\n", 402 (long)*kvers, (long)KERNEL_STARTUP_VERSION); 403 #endif 404 if (marks[MARK_NSYM] && (*kvers == 0x4e73 || *kvers <= 1)) { 405 nkcd = (int *)marks[MARK_SYM]; 406 esym = 0; 407 printf("Supressing %ld kernel symbols\n", marks[MARK_NSYM]); 408 timelimit = 60; 409 (void)getchar(); 410 } 411 /* version checks */ 412 putchar('\n'); 413 414 *nkcd = ncd; 415 kcd = (struct cfdev *)(nkcd + 1); 416 417 while ((cd = FindConfigDev(cd, -1, -1))) { 418 *kcd = *cd; 419 #ifndef PPCBOOTER 420 if (((cpuid >> 24) == 0x7D) && 421 ((u_long)kcd->addr < 0x1000000)) { 422 kcd->addr = (char *)kcd->addr + 0x3000000; 423 } 424 #endif 425 ++kcd; 426 } 427 428 nkcd = (int32_t *)kcd; 429 *nkcd = nseg; 430 431 kmemseg = (struct boot_memseg *)(nkcd + 1); 432 433 while (nseg-- > 0) 434 *kmemseg++ = *memseg++; 435 436 #ifdef PPCBOOTER 437 /* 438 * we use the ppc starter... 439 */ 440 start_it = startit; 441 #else 442 /* 443 * Copy startup code to end of kernel image and set start_it. 444 */ 445 memcpy((char *)kp + ksize + 256, (char *)startit, 446 (char *)startit_end - (char *)startit); 447 CacheClearU(); 448 start_it = (void *)((char *)kp + ksize + 256); 449 #endif 450 printf("*** Loading from %08lx to Fastmem %08lx ***\n", 451 (u_long)kp, (u_long)fmem); 452 /* sleep(2); */ 453 454 #if 0 455 printf("would start(kp=0x%lx, ksize=%ld, entry=0x%lx,\n" 456 "fmem=0x%lx, fmemsz=%ld, cmemsz=%ld\n" 457 "boothow=0x%lx, esym=0x%lx, cpuid=0x%lx, eclock=%ld\n" 458 "amigaflags=0x%lx, I_flags=0x%lx, ok?\n", 459 (u_long)kp, (u_long)ksize, marks[MARK_ENTRY] - marks[MARK_START], 460 (u_long)fmem, (u_long)fmemsz, (u_long)cmemsz, 461 (u_long)boothowto, (u_long)esym, (u_long)cpuid, (u_long)eclock, 462 (u_long)amiga_flags, (u_long)I_flag); 463 timelimit = 60; 464 (void)getchar(); 465 #endif 466 #ifdef DEBUG_MEMORY_LIST 467 timelimit = 0; 468 #else 469 timelimit = 2; 470 #endif 471 (void)getchar(); 472 473 #ifdef PPCBOOTER 474 startit 475 #else 476 start_it 477 #endif 478 (kp, ksize, marks[MARK_ENTRY] - marks[MARK_START], (void *)fmem, fmemsz, cmemsz, 479 boothowto, esym, cpuid, eclock, amiga_flags, I_flag, 480 aio_base >> 9, 1); 481 /*NOTREACHED*/ 482 483 freeall: 484 dealloc(kp, ksize); 485 err: 486 printf("\nError %ld\n", (long)errno); 487 goto again; 488 out: 489 timelimit = 10; 490 (void)getchar(); 491 return 1; 492 } 493 494 static 495 long get_number(char **ptr) 496 { 497 long value = 0; 498 int base = 10; 499 char *p = *ptr; 500 char c; 501 char sign = 0; 502 503 c = *++p; 504 while (c == ' ') 505 c = *++p; 506 if (c == '-') { 507 sign = -1; 508 c = *++p; 509 } 510 if (c == '$') { 511 base = 16; 512 c = *++p; 513 } else if (c == '0') { 514 c = *++p; 515 if ((c & 0xdf) == 'X') { 516 base = 16; 517 c = *++p; 518 } 519 } 520 while (c) { 521 if (c >= '0' && c <= '9') 522 c -= '0'; 523 else { 524 c = (c & 0xdf) - 'A' + 10; 525 if (base != 16 || c < 10 || c > 15) 526 break; 527 } 528 value = value * base + c; 529 c = *++p; 530 } 531 *ptr = p - 1; 532 #ifdef TEST 533 fprintf(stderr, "get_number: got %c0x%x", 534 sign ? '-' : '+', value); 535 #endif 536 return (sign ? -value : value); 537 } 538 539 /* 540 * Try to determine the machine ID by searching the resident module list 541 * for modules only present on specific machines. (Thanks, Bill!) 542 */ 543 544 int 545 get_cpuid(u_int32_t *cpuid) 546 { 547 uint8_t alicerev; 548 549 alicerev = *((uint8_t *)0xdff004) & 0x6f; 550 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */ 551 552 if (*cpuid & 0xffff0000) { 553 if ((*cpuid >> 24) == 0x7D) 554 return 0; 555 556 switch (*cpuid >> 16) { 557 case 500: 558 case 600: 559 case 1000: 560 case 1200: 561 case 2000: 562 case 3000: 563 case 4000: 564 return 0; 565 default: 566 printf("Amiga %ld ???\n", 567 (long)(*cpuid >> 16)); 568 return(1); 569 } 570 } 571 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus") 572 || FindResident("A1000 Bonus")) 573 *cpuid |= 4000 << 16; 574 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus") 575 || (SysBase->LibNode.Version == 36)) 576 *cpuid |= 3000 << 16; 577 else if (OpenResource("card.resource")) { 578 if (alicerev == 0x22 || alicerev == 0x23) 579 *cpuid |= 1200 << 16; /* AGA + PCMCIA = A1200 */ 580 else 581 *cpuid |= 600 << 16; /* noAGA + PCMCIA = A600 */ 582 } else if (OpenResource("draco.resource")) { 583 *cpuid |= (32000 | DRACOREVISION) << 16; 584 } 585 /* 586 * Nothing found, it's probably an A2000 or A500 587 */ 588 if ((*cpuid >> 16) == 0) 589 *cpuid |= 2000 << 16; 590 591 return 0; 592 } 593