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