1/* $NetBSD: boot.c,v 1.32 2024/01/07 07:58:33 isaki Exp $ */ 2 3/* 4 * Copyright (c) 2001 Minoura Makoto 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/param.h> 30#include <machine/bootinfo.h> 31 32#include <lib/libsa/stand.h> 33#include <lib/libsa/loadfile.h> 34#include <lib/libsa/ufs.h> 35#include <lib/libsa/dev_net.h> 36#include <lib/libkern/libkern.h> 37 38#include "libx68k.h" 39#include "iocs.h" 40#include "switch.h" 41 42#include "exec_image.h" 43 44 45#define HEAP_START ((void*) 0x00080000) 46#define HEAP_END ((void*) 0x000fffff) 47#define EXSCSI_BDID ((void*) 0x00ea0001) 48#define SRAM_MEMSIZE (*((long*) 0x00ed0008)) 49 50char default_kernel[20] = 51#if defined(NETBOOT) 52 "nfs:netbsd"; 53#else 54 "sd0a:netbsd"; 55#endif 56int mpu; 57int hostadaptor; 58int console_device = -1; 59 60#ifdef DEBUG 61int debug = 1; 62#endif 63 64static void help(void); 65static int get_scsi_host_adapter(void); 66static void doboot(const char *, int); 67static void boot(char *); 68static void cmd_ls(char *); 69int bootmenu(void); 70void bootmain(int); 71extern int detectmpu(void); 72extern int badbaddr(void *); 73 74extern struct fs_ops file_system_ustarfs[]; 75extern struct fs_ops file_system_nfs[]; 76 77/* from boot_ufs/bootmain.c */ 78static int 79get_scsi_host_adapter(void) 80{ 81 uint32_t bootinf; 82 char *bootrom; 83 int ha; 84 85 bootinf = IOCS_BOOTINF(); 86 if (bootinf < 0xa0) { 87 /* boot from FD */ 88 return 0; 89 } 90 91 /* Or, bootinf indicates the boot address */ 92 bootrom = (char *)(bootinf & 0x00ffffe0); 93 /* 94 * bootrom+0x24 "SCSIIN" ... Internal SCSI (spc0@) 95 * "SCSIEX" ... External SCSI (spc1@ or mha0@) 96 */ 97 if (*(u_short *)(bootrom + 0x24 + 4) == 0x494e) { /* "IN" */ 98 ha = (X68K_BOOT_SCSIIF_SPC << 4) | 0; 99 } else if (badbaddr(EXSCSI_BDID)) { 100 ha = (X68K_BOOT_SCSIIF_MHA << 4) | 0; 101 } else { 102 ha = (X68K_BOOT_SCSIIF_SPC << 4) | 1; 103 } 104 105 return ha; 106} 107 108static void 109help(void) 110{ 111 printf("Usage:\n"); 112 printf("boot [ha@][dev:][file] -[flags]\n"); 113 printf(" ha: spc0, spc1, mha0\n"); 114 printf(" dev: sd<ID><PART>, ID=0-7, PART=a-p\n"); 115 printf(" cd<ID>a, ID=0-7\n"); 116 printf(" fd<UNIT>a, UNIT=0-3, format is detected.\n"); 117 printf(" nfs, first probed NE2000 is used.\n"); 118 printf(" file: netbsd, netbsd.gz, etc.\n"); 119 printf(" flags: abdqsv\n"); 120 printf("ls [dev:][directory]\n"); 121 printf("switch [show | key=val]\n"); 122 printf("halt\nreboot\n"); 123} 124 125static void 126doboot(const char *file, int flags) 127{ 128 u_long marks[MARK_MAX]; 129 int fd; 130 int ha; /* host adaptor */ 131 int dev; /* device number in devspec[] */ 132 int unit; 133 int part; 134 int bootdev; 135 int maj; 136 char *name; 137 short *p; 138 int loadflag; 139 struct fs_ops *fs; 140 141 printf("Starting %s, flags 0x%x\n", file, flags); 142 143 if (devparse(file, &ha, &dev, &unit, &part, &name) != 0) { 144 printf("XXX: unknown corruption in /boot.\n"); 145 } 146 147#ifdef DEBUG 148 if (file[0] == 'n') { 149 printf("dev = %x, unit = %d, name = %s\n", 150 dev, unit, name); 151 } else { 152 printf("ha = 0x%x, dev = %x, unit = %d, part = %c, name = %s\n", 153 ha, dev, unit, part + 'a', name); 154 } 155#endif 156 157 if (dev == 3) { /* netboot */ 158 bootdev = X68K_MAKEBOOTDEV(X68K_MAJOR_NE, unit, 0); 159 } else if (dev == 2) { /* FD */ 160 bootdev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0); 161 } else { /* SCSI */ 162 if (ha != 0) { 163 hostadaptor = ha; 164 } 165 if (hostadaptor == 0) { 166 printf("host adaptor must be specified.\n"); 167 return; 168 } 169 170 maj = (dev == 0) ? X68K_MAJOR_SD : X68K_MAJOR_CD; 171 bootdev = X68K_MAKESCSIBOOTDEV(maj, 172 hostadaptor >> 4, 173 hostadaptor & 15, 174 unit & 7, 0, 0); 175 } 176#ifdef DEBUG 177 printf("boot device = %x\n", bootdev); 178 if (file[0] == 'n') { 179 printf("type = %x, if = %d, unit = %d\n", 180 B_TYPE(bootdev), 181 B_X68K_SCSI_IF(bootdev), 182 B_X68K_SCSI_IF_UN(bootdev)); 183 } else { 184 printf("type = %x, if = %d, unit = %d, id = %d, lun = %d, part = %c\n", 185 B_TYPE(bootdev), 186 B_X68K_SCSI_IF(bootdev), 187 B_X68K_SCSI_IF_UN(bootdev), 188 B_X68K_SCSI_ID(bootdev), 189 B_X68K_SCSI_LUN(bootdev), 190 B_X68K_SCSI_PART(bootdev) + 'a'); 191 } 192#endif 193 194 /* 195 * Choose the last entry of file_system[] at runtime. 196 * 197 * file_system[] is checked in turn from the beginning at all cases. 198 * Trying FS_OPS(ustarfs) for non-ustarfs displays "@" (as the 199 * mark which read a cylinder?). OTOH, trying FS_OPS(nfs) for 200 * non-nfs displays "must mount first" error message. 201 * It is better that neither is displayed and in other words you 202 * should not put these two into file_system[] at the same time. 203 * Therefore I choose one of these here. 204 */ 205 if (file[0] == 'n') { 206 fs = &file_system_nfs[0]; 207 } else { 208 fs = &file_system_ustarfs[0]; 209 } 210 memcpy(&file_system[nfsys - 1], fs, sizeof(*fs)); 211 212 loadflag = LOAD_KERNEL; 213 if (file[0] == 'f') 214 loadflag &= ~LOAD_BACKWARDS; 215 216 marks[MARK_START] = 0x100000; 217 if ((fd = loadfile(file, marks, loadflag)) == -1) { 218 printf("loadfile failed\n"); 219 return; 220 } 221 close(fd); 222 223 p = ((short*) marks[MARK_ENTRY]) - 1; 224#ifdef DEBUG 225 printf("Kernel Version: 0x%x\n", *p); 226#endif 227 if (*p != 0x4e73 && *p != 0) { 228 /* 229 * XXX temporary solution; compatibility loader 230 * must be written. 231 */ 232 printf("This kernel is too new to be loaded by " 233 "this version of /boot.\n"); 234 return; 235 } 236 237 exec_image(marks[MARK_START], 0, marks[MARK_ENTRY]-marks[MARK_START], 238 marks[MARK_END]-marks[MARK_START], bootdev, flags); 239 240 return; 241} 242 243static void 244boot(char *arg) 245{ 246 char filename[80]; 247 char *p; 248 int flags = 0; 249 250 if (*arg == 0 || *arg == '-') { 251 strcpy(filename, default_kernel); 252 if (*arg == '-') 253 if (parseopts(arg, &flags) == 0) { 254 help(); 255 return; 256 } 257 doboot(filename, flags); 258 return; 259 } else { 260 p = gettrailer(arg); 261 if (strchr(arg, ':')) { 262 strcpy(filename, arg); 263 if (arg[strlen(arg) - 1] == ':') 264 strcat(filename, "netbsd"); 265 } else { 266 strcpy(filename, default_kernel); 267 strcpy(strchr(filename, ':') + 1, arg); 268 } 269 if (*p == '-') { 270 if (parseopts(p, &flags) == 0) 271 return; 272 } else if (*p != 0) { 273 help(); 274 return; 275 } 276 277 doboot(filename, flags); 278 return; 279 } 280} 281 282static void 283cmd_ls(char *arg) 284{ 285 char filename[80]; 286 287 devopen_open_dir = 1; 288 if (*arg == 0) { 289 strcpy(filename, default_kernel); 290 strcpy(strchr(filename, ':')+1, "/"); 291 } else if (strchr(arg, ':') == 0) { 292 strcpy(filename, default_kernel); 293 strcpy(strchr(filename, ':')+1, arg); 294 } else { 295 strcpy(filename, arg); 296 if (*(strchr(arg, ':')+1) == 0) 297 strcat(filename, "/"); 298 } 299 ls(filename); 300 devopen_open_dir = 0; 301} 302 303int 304bootmenu(void) 305{ 306 char input[80]; 307 int n = 5, c; 308 309 printf("Press return to boot now, any other key for boot menu\n"); 310 printf("booting %s - starting in %d seconds. ", 311 default_kernel, n); 312 while (n-- > 0 && (c = awaitkey_1sec()) == 0) { 313 printf("\r"); 314 printf("booting %s - starting in %d seconds. ", 315 default_kernel, n); 316 } 317 printf("\r"); 318 printf("booting %s - starting in %d seconds. ", default_kernel, 0); 319 printf("\n"); 320 321 if (c == 0 || c == '\r') { 322 doboot(default_kernel, 0); 323 printf("Could not start %s; ", default_kernel); 324 strcat(default_kernel, ".gz"); 325 printf("trying %s.\n", default_kernel); 326 doboot(default_kernel, 0); 327 printf("Could not start %s; ", default_kernel); 328 } 329 330 printf("Please use the absolute unit# (e.g. SCSI ID)" 331 " instead of the NetBSD logical #.\n"); 332 for (;;) { 333 char *p, *options; 334 335 printf("> "); 336 kgets(input, sizeof(input)); 337 338 for (p = &input[0]; p - &input[0] < 80 && *p == ' '; p++) 339 ; 340 options = gettrailer(p); 341 if (strcmp("boot", p) == 0) 342 boot(options); 343 else if (strcmp("help", p) == 0 || 344 strcmp("?", p) == 0) 345 help(); 346 else if (strcmp("halt", p) == 0 || 347 strcmp("reboot", p) == 0) 348 exit(0); 349 else if (strcmp("switch", p) == 0) 350 cmd_switch(options); 351 else if (strcmp("ls", p) == 0) 352 cmd_ls(options); 353 else 354 printf("Unknown command %s\n", p); 355 } 356} 357 358static u_int 359checkmemsize(void) 360{ 361 u_int m; 362 363#define MIN_MB 4 364#define MAX_MB 12 365 366 for (m = MIN_MB; m <= MAX_MB; m++) { 367 if (badbaddr((void *)(m * 1024 * 1024 - 1))) { 368 /* no memory */ 369 break; 370 } 371 } 372 373 return (m - 1) * 1024 * 1024; 374} 375 376extern const char bootprog_rev[]; 377extern const char bootprog_name[]; 378 379/* 380 * Arguments from the boot block: 381 * bootdev - specifies the device from which /boot was read, in 382 * bootdev format. 383 */ 384void 385bootmain(int bootdev) 386{ 387 u_int sram_memsize; 388 u_int probed_memsize; 389 390 console_device = consio_init(console_device); 391 392 hostadaptor = get_scsi_host_adapter(); 393 rtc_offset = RTC_OFFSET; 394 try_bootp = 1; 395 mpu = detectmpu(); 396 397 if (mpu < 3) { /* not tested on 68020 */ 398 printf("This MPU cannot run NetBSD.\n"); 399 exit(1); 400 } 401 sram_memsize = SRAM_MEMSIZE; 402 if (sram_memsize < 4*1024*1024) { 403 printf("Main memory too small.\n"); 404 exit(1); 405 } 406 407 setheap(HEAP_START, HEAP_END); 408 409#if !defined(NETBOOT) 410 switch (B_TYPE(bootdev)) { 411 case X68K_MAJOR_FD: 412 default_kernel[0] = 'f'; 413 default_kernel[2] = '0' + B_UNIT(bootdev); 414 default_kernel[3] = 'a'; 415 break; 416 case X68K_MAJOR_SD: 417 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 418 default_kernel[3] = 419 'a' + sd_getbsdpartition(B_X68K_SCSI_ID(bootdev), 420 B_X68K_SCSI_PART(bootdev)); 421 break; 422 case X68K_MAJOR_CD: 423 default_kernel[0] = 'c'; 424 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 425 default_kernel[3] = 'a'; 426 break; 427 default: 428 printf("Warning: unknown boot device: %x\n", bootdev); 429 } 430#endif 431 print_title("%s, Revision %s\n", bootprog_name, bootprog_rev); 432 433 /* check actual memory size for machines with a dead SRAM battery */ 434 probed_memsize = checkmemsize(); 435 if (sram_memsize != probed_memsize) { 436 printf("\x1b[1mWarning: SRAM Memory Size (%d MB) " 437 "is different from probed Memory Size (%d MB)\n" 438 " Check and reset SRAM values.\x1b[m\n\n", 439 sram_memsize / (1024 * 1024), 440 probed_memsize / (1024 * 1024)); 441 } 442 443 bootmenu(); 444} 445