1 /* $NetBSD: boot.c,v 1.22 2014/08/05 13:49:04 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 #ifdef NETBOOT 36 #include <lib/libsa/dev_net.h> 37 #endif 38 #include <lib/libkern/libkern.h> 39 40 #include "libx68k.h" 41 #include "iocs.h" 42 #include "switch.h" 43 44 #include "exec_image.h" 45 46 47 #define HEAP_START ((void*) 0x00080000) 48 #define HEAP_END ((void*) 0x000fffff) 49 #define EXSCSI_BDID ((void*) 0x00ea0001) 50 #define SRAM_MEMSIZE (*((long*) 0x00ed0008)) 51 52 char default_kernel[20] = 53 #ifndef NETBOOT 54 "sd0a:netbsd"; 55 #else 56 "nfs:netbsd"; 57 #endif 58 int mpu; 59 #ifndef NETBOOT 60 int hostadaptor; 61 #endif 62 int console_device = -1; 63 64 #ifdef DEBUG 65 #ifdef NETBOOT 66 int debug = 1; 67 #endif 68 #endif 69 70 static void help(void); 71 #ifndef NETBOOT 72 static int get_scsi_host_adapter(void); 73 #endif 74 static void doboot(const char *, int); 75 static void boot(char *); 76 #ifndef NETBOOT 77 static void cmd_ls(char *); 78 #endif 79 int bootmenu(void); 80 void bootmain(int); 81 extern int detectmpu(void); 82 extern int badbaddr(void *); 83 84 #ifndef NETBOOT 85 /* from boot_ufs/bootmain.c */ 86 static int 87 get_scsi_host_adapter(void) 88 { 89 char *bootrom; 90 int ha; 91 92 bootrom = (char *) (IOCS_BOOTINF() & 0x00ffffe0); 93 /* 94 * bootrom+0x24 "SCSIIN" ... Internal SCSI (spc@0) 95 * "SCSIEX" ... External SCSI (spc@1 or mha@0) 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 #endif 108 109 static void 110 help(void) 111 { 112 printf("Usage:\n"); 113 printf("boot [dev:][file] -[flags]\n"); 114 #ifndef NETBOOT 115 printf(" dev: sd<ID><PART>, ID=0-7, PART=a-p\n"); 116 printf(" cd<ID>a, ID=0-7\n"); 117 printf(" fd<UNIT>a, UNIT=0-3, format is detected.\n"); 118 #else 119 printf(" dev: nfs, first probed NE2000 is used.\n"); 120 #endif 121 printf(" file: netbsd, netbsd.gz, etc.\n"); 122 printf(" flags: abdqsv\n"); 123 #ifndef NETBOOT 124 printf("ls [dev:][directory]\n"); 125 #endif 126 printf("switch [show | key=val]\n"); 127 printf("halt\nreboot\n"); 128 } 129 130 static void 131 doboot(const char *file, int flags) 132 { 133 u_long marks[MARK_MAX]; 134 int fd; 135 int dev, unit, part; 136 char *name; 137 short *p; 138 int loadflag; 139 140 printf("Starting %s, flags 0x%x\n", file, flags); 141 142 loadflag = LOAD_KERNEL; 143 if (file[0] == 'f') 144 loadflag &= ~LOAD_BACKWARDS; 145 146 marks[MARK_START] = 0x100000; 147 if ((fd = loadfile(file, marks, loadflag)) == -1) { 148 printf("loadfile failed\n"); 149 return; 150 } 151 close(fd); 152 153 if (devparse(file, &dev, &unit, &part, &name) != 0) { 154 printf("XXX: unknown corruption in /boot.\n"); 155 } 156 157 #ifdef DEBUG 158 #ifndef NETBOOT 159 printf("dev = %x, unit = %d, part = %c, name = %s\n", 160 dev, unit, part + 'a', name); 161 #else 162 printf("dev = %x, unit = %d, name = %s\n", 163 dev, unit, name); 164 #endif 165 #endif 166 167 #ifndef NETBOOT 168 if (dev == 0) { /* SCSI */ 169 dev = X68K_MAKESCSIBOOTDEV(X68K_MAJOR_SD, 170 hostadaptor >> 4, 171 hostadaptor & 15, 172 unit & 7, 0, 0); 173 } else { 174 dev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0); 175 } 176 #else 177 dev = X68K_MAKEBOOTDEV(X68K_MAJOR_NE, unit, 0); 178 #endif 179 #ifdef DEBUG 180 printf("boot device = %x\n", dev); 181 #ifndef NETBOOT 182 printf("if = %d, unit = %d, id = %d, lun = %d, part = %c\n", 183 B_X68K_SCSI_IF(dev), 184 B_X68K_SCSI_IF_UN(dev), 185 B_X68K_SCSI_ID(dev), 186 B_X68K_SCSI_LUN(dev), 187 B_X68K_SCSI_PART(dev) + 'a'); 188 #else 189 printf("if = %d, unit = %d\n", 190 B_X68K_SCSI_IF(dev), 191 B_X68K_SCSI_IF_UN(dev)); 192 #endif 193 #endif 194 195 p = ((short*) marks[MARK_ENTRY]) - 1; 196 #ifdef DEBUG 197 printf("Kernel Version: 0x%x\n", *p); 198 #endif 199 if (*p != 0x4e73 && *p != 0) { 200 /* 201 * XXX temporary solution; compatibility loader 202 * must be written. 203 */ 204 printf("This kernel is too new to be loaded by " 205 "this version of /boot.\n"); 206 return; 207 } 208 209 exec_image(marks[MARK_START], 0, marks[MARK_ENTRY]-marks[MARK_START], 210 marks[MARK_END]-marks[MARK_START], dev, flags); 211 212 return; 213 } 214 215 static void 216 boot(char *arg) 217 { 218 char filename[80]; 219 char *p; 220 int flags = 0; 221 222 if (*arg == 0 || *arg == '-') { 223 strcpy(filename, default_kernel); 224 if (*arg == '-') 225 if (parseopts(arg, &flags) == 0) { 226 help(); 227 return; 228 } 229 doboot(filename, flags); 230 return; 231 } else { 232 p = gettrailer(arg); 233 if (strchr(arg, ':')) { 234 strcpy(filename, arg); 235 if (arg[strlen(arg) - 1] == ':') 236 strcat(filename, "netbsd"); 237 } else { 238 strcpy(filename, default_kernel); 239 strcpy(strchr(filename, ':') + 1, arg); 240 } 241 if (*p == '-') { 242 if (parseopts(p, &flags) == 0) 243 return; 244 } else if (*p != 0) { 245 help(); 246 return; 247 } 248 249 doboot(filename, flags); 250 return; 251 } 252 } 253 254 #ifndef NETBOOT 255 static void 256 cmd_ls(char *arg) 257 { 258 char filename[80]; 259 260 devopen_open_dir = 1; 261 if (*arg == 0) { 262 strcpy(filename, default_kernel); 263 strcpy(strchr(filename, ':')+1, "/"); 264 } else if (strchr(arg, ':') == 0) { 265 strcpy(filename, default_kernel); 266 strcpy(strchr(filename, ':')+1, arg); 267 } else { 268 strcpy(filename, arg); 269 if (*(strchr(arg, ':')+1) == 0) 270 strcat(filename, "/"); 271 } 272 ls(filename); 273 devopen_open_dir = 0; 274 } 275 #endif 276 277 int 278 bootmenu(void) 279 { 280 char input[80]; 281 int n = 5, c; 282 283 printf("Press return to boot now, any other key for boot menu\n"); 284 printf("booting %s - starting in %d seconds. ", 285 default_kernel, n); 286 while (n-- > 0 && (c = awaitkey_1sec()) == 0) { 287 printf("\r"); 288 printf("booting %s - starting in %d seconds. ", 289 default_kernel, n); 290 } 291 printf("\r"); 292 printf("booting %s - starting in %d seconds. ", default_kernel, 0); 293 printf("\n"); 294 295 if (c == 0 || c == '\r') { 296 doboot(default_kernel, 0); 297 printf("Could not start %s; ", default_kernel); 298 strcat(default_kernel, ".gz"); 299 printf("trying %s.\n", default_kernel); 300 doboot(default_kernel, 0); 301 printf("Could not start %s; ", default_kernel); 302 } 303 304 printf("Please use the absolute unit# (e.g. SCSI ID)" 305 " instead of the NetBSD logical #.\n"); 306 for (;;) { 307 char *p, *options; 308 309 printf("> "); 310 gets(input); 311 312 for (p = &input[0]; p - &input[0] < 80 && *p == ' '; p++) 313 ; 314 options = gettrailer(p); 315 if (strcmp("boot", p) == 0) 316 boot(options); 317 else if (strcmp("help", p) == 0 || 318 strcmp("?", p) == 0) 319 help(); 320 else if (strcmp("halt", p) == 0 || 321 strcmp("reboot", p) == 0) 322 exit(0); 323 else if (strcmp("switch", p) == 0) 324 cmd_switch(options); 325 #ifndef NETBOOT 326 else if (strcmp("ls", p) == 0) 327 cmd_ls(options); 328 #endif 329 else 330 printf("Unknown command %s\n", p); 331 } 332 } 333 334 static u_int 335 checkmemsize(void) 336 { 337 u_int m; 338 339 #define MIN_MB 4 340 #define MAX_MB 12 341 342 for (m = MIN_MB; m <= MAX_MB; m++) { 343 if (badbaddr((void *)(m * 1024 * 1024 - 1))) { 344 /* no memory */ 345 break; 346 } 347 } 348 349 return (m - 1) * 1024 * 1024; 350 } 351 352 extern const char bootprog_rev[]; 353 extern const char bootprog_name[]; 354 355 /* 356 * Arguments from the boot block: 357 * bootdev - specifies the device from which /boot was read, in 358 * bootdev format. 359 */ 360 void 361 bootmain(int bootdev) 362 { 363 u_int sram_memsize; 364 u_int probed_memsize; 365 366 #ifndef NETBOOT 367 hostadaptor = get_scsi_host_adapter(); 368 #else 369 rtc_offset = RTC_OFFSET; 370 try_bootp = 1; 371 #endif 372 mpu = detectmpu(); 373 374 if (mpu < 3) { /* not tested on 68020 */ 375 printf("This MPU cannot run NetBSD.\n"); 376 exit(1); 377 } 378 sram_memsize = SRAM_MEMSIZE; 379 if (sram_memsize < 4*1024*1024) { 380 printf("Main memory too small.\n"); 381 exit(1); 382 } 383 384 console_device = consio_init(console_device); 385 setheap(HEAP_START, HEAP_END); 386 387 #ifndef NETBOOT 388 switch (B_TYPE(bootdev)) { 389 case X68K_MAJOR_FD: 390 default_kernel[0] = 'f'; 391 default_kernel[2] = '0' + B_UNIT(bootdev); 392 default_kernel[3] = 'a'; 393 break; 394 case X68K_MAJOR_SD: 395 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 396 default_kernel[3] = 397 'a' + sd_getbsdpartition(B_X68K_SCSI_ID(bootdev), 398 B_X68K_SCSI_PART(bootdev)); 399 break; 400 case X68K_MAJOR_CD: 401 default_kernel[0] = 'c'; 402 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 403 default_kernel[3] = 'a'; 404 break; 405 default: 406 printf("Warning: unknown boot device: %x\n", bootdev); 407 } 408 #endif 409 print_title("%s, Revision %s\n", bootprog_name, bootprog_rev); 410 411 /* check actual memory size for machines with a dead SRAM battery */ 412 probed_memsize = checkmemsize(); 413 if (sram_memsize != probed_memsize) { 414 printf("\x1b[1mWarning: SRAM Memory Size (%d MB) " 415 "is different from probed Memory Size (%d MB)\n" 416 " Check and reset SRAM values.\x1b[m\n\n", 417 sram_memsize / (1024 * 1024), 418 probed_memsize / (1024 * 1024)); 419 } 420 421 bootmenu(); 422 } 423