1 /* 2 * $NetBSD: main.c,v 1.32 2021/12/05 08:09:30 msaitoh 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 int8_t mempri; 126 127 int ncd, nseg; 128 char c; 129 130 u_long marks[MARK_MAX]; 131 132 extern u_int16_t timelimit; 133 134 extern u_int32_t aio_base; 135 136 xdinit(aio); 137 138 if (consinit(cons)) 139 return(1); 140 141 /* 142 * we need V36 for: EClock, RDB Bootblocks, CacheClearU 143 */ 144 145 if (SysBase->LibNode.Version < EXECMIN) { 146 printf("Exec V%ld, need V%ld\n", 147 (long)SysBase->LibNode.Version, (long)EXECMIN); 148 goto out; 149 } 150 151 /* 152 * XXX Do this differently; default boot will attempt to load a list of 153 * XXX kernels until one of them succeeds. 154 */ 155 timelimit = 3; 156 again: 157 #ifdef PPCBOOTER 158 printf("\nNetBSD/AmigaPPC " NETBSD_VERS " Bootstrap, Revision %s\n", 159 bootprog_rev); 160 #else 161 printf("\nNetBSD/Amiga " NETBSD_VERS " Bootstrap, Revision %s\n", 162 bootprog_rev); 163 #endif 164 printf("\n"); 165 printf("Boot: [%s] ", kernel_name); 166 167 kgets(linebuf, sizeof(linebuf)); 168 169 if (*linebuf == 'q') 170 return 1; 171 172 if (*linebuf) 173 path = linebuf; 174 175 /* 176 * parse boot command for path name and process any options 177 */ 178 while ((c = *path)) { 179 while (c == ' ') 180 c = *++path; 181 if (c == '-') { 182 while ((c = *++path) && c != ' ') { 183 switch (c) { 184 case 'a': /* multi-user state */ 185 boothowto &= ~RB_SINGLE; 186 break; 187 case 'b': /* ask for root device */ 188 boothowto |= RB_ASKNAME; 189 break; 190 case 'c': /* force machine model */ 191 cpuid = get_number(&path) << 16; 192 break; 193 case 'k': /* Reserve first 4M fastmem */ 194 k_flag++; 195 break; 196 case 'm': /* Force fastmem size */ 197 m_value = get_number(&path) * 1024; 198 break; 199 case 'n': /* non-contiguous memory */ 200 amiga_flags |= 201 (get_number(&path) & 3) << 1; 202 break; 203 case 'p': /* Select fastmem by priority */ 204 p_flag = 1; 205 break; 206 case 'q': 207 boothowto |= AB_QUIET; 208 break; 209 case 's': /* single-user state */ 210 boothowto |= RB_SINGLE; 211 break; 212 case 't': /* test flag */ 213 /* t_flag = 1; */ 214 break; 215 case 'v': 216 boothowto |= AB_VERBOSE; 217 break; 218 case 'A': /* enable AGA modes */ 219 amiga_flags |= 1; 220 break; 221 case 'C': /* Serial Console */ 222 amiga_flags |= (1 << 3); 223 break; 224 case 'D': /* enter Debugger */ 225 boothowto |= RB_KDB; 226 break; 227 case 'I': /* inhibit sync negotiation */ 228 I_flag = get_number(&path); 229 break; 230 case 'K': /* remove 1st 4MB fastmem */ 231 break; 232 case 'S': /* include debug symbols */ 233 S_flag = 1; 234 break; 235 } 236 } 237 } else { 238 /* XXX Handle kernel_name differently */ 239 kernel_name = path; 240 while ((c = *++path) && c != ' ') 241 ; 242 if (c) 243 *path++ = 0; 244 } 245 } 246 /* XXX Handle kernel_name differently */ 247 while ((c = *kernel_name) && c == ' ') 248 ++kernel_name; 249 path = kernel_name; 250 while ((c = *path) && c != ' ') 251 ++path; 252 if (c) 253 *path = 0; 254 255 if (get_cpuid(&cpuid)) 256 goto out; 257 258 ExpansionBase = OpenLibrary("expansion.library", 0); 259 if (!ExpansionBase) { 260 printf("can't open %s\n", "expansion.library"); 261 return 1; 262 } 263 264 for (ncd=0, cd=0; (cd = FindConfigDev(cd, -1, -1)); ncd++) 265 /* nothing */; 266 267 /* find memory list */ 268 269 memseg = (struct boot_memseg *)alloc(16*sizeof(struct boot_memseg)); 270 271 /* Forbid(); */ 272 273 nseg = 0; 274 mh = SysBase->MemLst; 275 vfrom = mh->Lower & -__PGSZ; 276 vsize = (mh->Upper & -__PGSZ) - vfrom; 277 contflag = mapped1to1 = 0; 278 mempri = -128; 279 280 do { 281 size = vsize; 282 283 if (SysBase->LibNode.Version > 36) { 284 from = CachePreDMA(vfrom, &size, contflag); 285 contflag = DMAF_Continue; 286 mapped1to1 = (from == vfrom); 287 vsize -= size; 288 vfrom += size; 289 } else { 290 from = vfrom; 291 mapped1to1 = 1; 292 vsize = 0; 293 } 294 295 #ifdef DEBUG_MEMORY_LIST 296 printf("%lx %lx %lx %ld/%lx %lx\n", 297 (long)from, (long)size, 298 (long)mh->Attribs, (long)mh->Pri, 299 (long)vfrom, (long)vsize); 300 #endif 301 /* Insert The Evergrowing Kludge List Here: */ 302 303 /* a) dont load kernel over DraCo MMU table */ 304 305 if (((cpuid >> 24) == 0x7D) && 306 ((from & -DRACOMMUMARGIN) == 0x40000000) && 307 (size >= DRACOMMUMARGIN)) { 308 309 memseg[nseg].ms_start = from & -DRACOMMUMARGIN; 310 memseg[nseg].ms_size = DRACOMMUMARGIN; 311 memseg[nseg].ms_attrib = mh->Attribs; 312 memseg[nseg].ms_pri = mh->Pri; 313 314 size -= DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 315 from += DRACOMMUMARGIN - (from & (DRACOMMUMARGIN - 1)); 316 ++nseg; 317 } 318 319 if ((mh->Attribs & (MEMF_CHIP|MEMF_FAST)) == MEMF_CHIP) { 320 size += from; 321 cmemsz = size; 322 from = 0; 323 } else if (mapped1to1 && ((!p_flag && fmemsz < size) || 324 (p_flag && (mempri < mh->Pri || 325 (mempri == mh->Pri && fmemsz < size))))) { 326 fmem = from; 327 fmemsz = size; 328 mempri = mh->Pri; 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("Suppressing %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 = (char *)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((char *)kp + ksize + 256, (char *)startit, 451 (char *)startit_end - (char *)startit); 452 CacheClearU(); 453 start_it = (void *)((char *)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 uint8_t alicerev; 553 554 alicerev = *((uint8_t *)0xdff004) & 0x6f; 555 *cpuid |= SysBase->AttnFlags; /* get FPU and CPU flags */ 556 557 if (*cpuid & 0xffff0000) { 558 if ((*cpuid >> 24) == 0x7D) 559 return 0; 560 561 switch (*cpuid >> 16) { 562 case 500: 563 case 600: 564 case 1000: 565 case 1200: 566 case 2000: 567 case 3000: 568 case 4000: 569 return 0; 570 default: 571 printf("Amiga %ld ???\n", 572 (long)(*cpuid >> 16)); 573 return(1); 574 } 575 } 576 if (FindResident("A4000 Bonus") || FindResident("A4000 bonus") 577 || FindResident("A1000 Bonus")) 578 *cpuid |= 4000 << 16; 579 else if (FindResident("A3000 Bonus") || FindResident("A3000 bonus") 580 || (SysBase->LibNode.Version == 36)) 581 *cpuid |= 3000 << 16; 582 else if (OpenResource("card.resource")) { 583 if (alicerev == 0x22 || alicerev == 0x23) 584 *cpuid |= 1200 << 16; /* AGA + PCMCIA = A1200 */ 585 else 586 *cpuid |= 600 << 16; /* noAGA + PCMCIA = A600 */ 587 } else if (OpenResource("draco.resource")) { 588 *cpuid |= (32000 | DRACOREVISION) << 16; 589 } 590 /* 591 * Nothing found, it's probably an A2000 or A500 592 */ 593 if ((*cpuid >> 16) == 0) 594 *cpuid |= 2000 << 16; 595 596 return 0; 597 } 598