1 /* $NetBSD: boot.c,v 1.18 2012/03/20 12:37:01 minoura 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/libkern/libkern.h> 36 37 #include "libx68k.h" 38 #include "iocs.h" 39 40 #include "exec_image.h" 41 42 43 #define HEAP_START ((void*) 0x00080000) 44 #define HEAP_END ((void*) 0x000fffff) 45 #define EXSCSI_BDID ((void*) 0x00ea0001) 46 #define SRAM_MEMSIZE (*((long*) 0x00ed0008)) 47 48 char default_kernel[20] = "sd0a:netbsd"; 49 int mpu, hostadaptor; 50 int console_device = -1; 51 52 static void help(void); 53 static int get_scsi_host_adapter(void); 54 static void doboot(const char *, int); 55 static void boot(char *); 56 static void cmd_ls(char *); 57 int bootmenu(void); 58 void bootmain(int); 59 extern int detectmpu(void); 60 extern int badbaddr(void *); 61 62 /* from boot_ufs/bootmain.c */ 63 static int 64 get_scsi_host_adapter(void) 65 { 66 char *bootrom; 67 int ha; 68 69 bootrom = (char *) (IOCS_BOOTINF() & 0x00ffffe0); 70 /* 71 * bootrom+0x24 "SCSIIN" ... Internal SCSI (spc@0) 72 * "SCSIEX" ... External SCSI (spc@1 or mha@0) 73 */ 74 if (*(u_short *)(bootrom + 0x24 + 4) == 0x494e) { /* "IN" */ 75 ha = (X68K_BOOT_SCSIIF_SPC << 4) | 0; 76 } else if (badbaddr(EXSCSI_BDID)) { 77 ha = (X68K_BOOT_SCSIIF_MHA << 4) | 0; 78 } else { 79 ha = (X68K_BOOT_SCSIIF_SPC << 4) | 1; 80 } 81 82 return ha; 83 } 84 85 86 static void 87 help(void) 88 { 89 printf("Usage:\n"); 90 printf("boot [dev:][file] -[flags]\n"); 91 printf(" dev: sd<ID><PART>, ID=0-7, PART=a-p\n"); 92 printf(" cd<ID>a, ID=0-7\n"); 93 printf(" fd<UNIT>a, UNIT=0-3, format is detected.\n"); 94 printf(" file: netbsd, netbsd.gz, etc.\n"); 95 printf(" flags: abdqsv\n"); 96 printf("ls [dev:][directory]\n"); 97 printf("halt\nreboot\n"); 98 } 99 100 static void 101 doboot(const char *file, int flags) 102 { 103 u_long marks[MARK_MAX]; 104 int fd; 105 int dev, unit, part; 106 char *name; 107 short *p; 108 int loadflag; 109 110 printf("Starting %s, flags 0x%x\n", file, flags); 111 112 loadflag = LOAD_KERNEL; 113 if (file[0] == 'f') 114 loadflag &= ~LOAD_BACKWARDS; 115 116 marks[MARK_START] = 0x100000; 117 if ((fd = loadfile(file, marks, loadflag)) == -1) { 118 printf("loadfile failed\n"); 119 return; 120 } 121 close(fd); 122 123 if (devparse(file, &dev, &unit, &part, &name) != 0) { 124 printf("XXX: unknown corruption in /boot.\n"); 125 } 126 127 #ifdef DEBUG 128 printf("dev = %x, unit = %d, part = %c, name = %s\n", 129 dev, unit, part + 'a', name); 130 #endif 131 132 if (dev == 0) { /* SCSI */ 133 dev = X68K_MAKESCSIBOOTDEV(X68K_MAJOR_SD, 134 hostadaptor >> 4, 135 hostadaptor & 15, 136 unit & 7, 0, 0); 137 } else { 138 dev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0); 139 } 140 #ifdef DEBUG 141 printf("boot device = %x\n", dev); 142 printf("if = %d, unit = %d, id = %d, lun = %d, part = %c\n", 143 B_X68K_SCSI_IF(dev), 144 B_X68K_SCSI_IF_UN(dev), 145 B_X68K_SCSI_ID(dev), 146 B_X68K_SCSI_LUN(dev), 147 B_X68K_SCSI_PART(dev) + 'a'); 148 #endif 149 150 p = ((short*) marks[MARK_ENTRY]) - 1; 151 #ifdef DEBUG 152 printf("Kernel Version: 0x%x\n", *p); 153 #endif 154 if (*p != 0x4e73 && *p != 0) { 155 /* 156 * XXX temporary solution; compatibility loader 157 * must be written. 158 */ 159 printf("This kernel is too new to be loaded by " 160 "this version of /boot.\n"); 161 return; 162 } 163 164 exec_image(marks[MARK_START], 0, marks[MARK_ENTRY]-marks[MARK_START], 165 marks[MARK_END]-marks[MARK_START], dev, flags); 166 167 return; 168 } 169 170 static void 171 boot(char *arg) 172 { 173 char filename[80]; 174 char *p; 175 int flags = 0; 176 177 if (*arg == 0 || *arg == '-') { 178 strcpy(filename, default_kernel); 179 if (*arg == '-') 180 if (parseopts(arg, &flags) == 0) { 181 help(); 182 return; 183 } 184 doboot(filename, flags); 185 return; 186 } else { 187 p = gettrailer(arg); 188 if (strchr(arg, ':')) { 189 strcpy(filename, arg); 190 if (arg[strlen(arg) - 1] == ':') 191 strcat(filename, "netbsd"); 192 } else { 193 strcpy(filename, default_kernel); 194 strcpy(strchr(filename, ':') + 1, arg); 195 } 196 if (*p == '-') { 197 if (parseopts(p, &flags) == 0) 198 return; 199 } else if (*p != 0) { 200 help(); 201 return; 202 } 203 204 doboot(filename, flags); 205 return; 206 } 207 } 208 209 static void 210 cmd_ls(char *arg) 211 { 212 char filename[80]; 213 214 devopen_open_dir = 1; 215 if (*arg == 0) { 216 strcpy(filename, default_kernel); 217 strcpy(strchr(filename, ':')+1, "/"); 218 } else if (strchr(arg, ':') == 0) { 219 strcpy(filename, default_kernel); 220 strcpy(strchr(filename, ':')+1, arg); 221 } else { 222 strcpy(filename, arg); 223 if (*(strchr(arg, ':')+1) == 0) 224 strcat(filename, "/"); 225 } 226 ls(filename); 227 devopen_open_dir = 0; 228 } 229 230 int 231 bootmenu(void) 232 { 233 char input[80]; 234 int n = 5, c; 235 236 printf("Press return to boot now, any other key for boot menu\n"); 237 printf("booting %s - starting in %d seconds. ", 238 default_kernel, n); 239 while (n-- > 0 && (c = awaitkey_1sec()) == 0) { 240 printf("\r"); 241 printf("booting %s - starting in %d seconds. ", 242 default_kernel, n); 243 } 244 printf("\r"); 245 printf("booting %s - starting in %d seconds. ", default_kernel, 0); 246 printf("\n"); 247 248 if (c == 0 || c == '\r') { 249 doboot(default_kernel, 0); 250 printf("Could not start %s; ", default_kernel); 251 strcat(default_kernel, ".gz"); 252 printf("trying %s.\n", default_kernel); 253 doboot(default_kernel, 0); 254 printf("Could not start %s; ", default_kernel); 255 } 256 257 printf("Please use the absolute unit# (e.g. SCSI ID)" 258 " instead of the NetBSD logical #.\n"); 259 for (;;) { 260 char *p, *options; 261 262 printf("> "); 263 gets(input); 264 265 for (p = &input[0]; p - &input[0] < 80 && *p == ' '; p++); 266 options = gettrailer(p); 267 if (strcmp("boot", p) == 0) 268 boot(options); 269 else if (strcmp("help", p) == 0 || 270 strcmp("?", p) == 0) 271 help(); 272 else if ((strcmp("halt", p) == 0) ||(strcmp("reboot", p) == 0)) 273 exit(0); 274 else if (strcmp("ls", p) == 0) 275 cmd_ls(options); 276 else 277 printf("Unknown command %s\n", p); 278 } 279 } 280 281 282 extern const char bootprog_rev[]; 283 extern const char bootprog_name[]; 284 285 /* 286 * Arguments from the boot block: 287 * bootdev - specifies the device from which /boot was read, in 288 * bootdev format. 289 */ 290 void 291 bootmain(int bootdev) 292 { 293 hostadaptor = get_scsi_host_adapter(); 294 mpu = detectmpu(); 295 296 if (mpu < 3) { /* not tested on 68020 */ 297 printf("This MPU cannot run NetBSD.\n"); 298 exit(1); 299 } 300 if (SRAM_MEMSIZE < 4*1024*1024) { 301 printf("Main memory too small.\n"); 302 exit(1); 303 } 304 305 console_device = consio_init(console_device); 306 setheap(HEAP_START, HEAP_END); 307 308 switch (B_TYPE(bootdev)) { 309 case X68K_MAJOR_FD: 310 default_kernel[0] = 'f'; 311 default_kernel[2] = '0' + B_UNIT(bootdev); 312 default_kernel[3] = 'a'; 313 break; 314 case X68K_MAJOR_SD: 315 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 316 default_kernel[3] = 317 'a' + sd_getbsdpartition(B_X68K_SCSI_ID(bootdev), 318 B_X68K_SCSI_PART(bootdev)); 319 break; 320 case X68K_MAJOR_CD: 321 default_kernel[0] = 'c'; 322 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 323 default_kernel[3] = 'a'; 324 break; 325 default: 326 printf("Warning: unknown boot device: %x\n", bootdev); 327 } 328 print_title("%s, Revision %s\n", bootprog_name, bootprog_rev); 329 bootmenu(); 330 } 331