1 /* $NetBSD: boot.c,v 1.13 2007/10/17 19:58:03 garbled 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 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 109 printf("Starting %s, flags 0x%x\n", file, flags); 110 marks[MARK_START] = 0x100000; 111 if ((fd = loadfile(file, marks, LOAD_KERNEL)) == -1) { 112 printf("loadfile failed\n"); 113 return; 114 } 115 close(fd); 116 117 if (devparse(file, &dev, &unit, &part, &name) != 0) { 118 printf("XXX: unknown corruption in /boot.\n"); 119 } 120 121 printf("dev = %x, unit = %d, part = %c, name = %s\n", 122 dev, unit, part + 'a', name); 123 124 if (dev == 0) { /* SCSI */ 125 dev = X68K_MAKESCSIBOOTDEV(X68K_MAJOR_SD, 126 hostadaptor >> 4, 127 hostadaptor & 15, 128 unit & 7, 0, 0); 129 } else { 130 dev = X68K_MAKEBOOTDEV(X68K_MAJOR_FD, unit & 3, 0); 131 } 132 printf("boot device = %x\n", dev); 133 printf("if = %d, unit = %d, id = %d, lun = %d, part = %c\n", 134 B_X68K_SCSI_IF(dev), 135 B_X68K_SCSI_IF_UN(dev), 136 B_X68K_SCSI_ID(dev), 137 B_X68K_SCSI_LUN(dev), 138 B_X68K_SCSI_PART(dev) + 'a'); 139 140 p = ((short*) marks[MARK_ENTRY]) - 1; 141 printf("Kernel Version: 0x%x\n", *p); 142 if (*p != 0x4e73 && *p != 0) { 143 /* 144 * XXX temporary solution; compatibility loader 145 * must be written. 146 */ 147 printf("This kernel is too new to be loaded by " 148 "this version of /boot.\n"); 149 return; 150 } 151 152 exec_image(marks[MARK_START], 0, marks[MARK_ENTRY]-marks[MARK_START], 153 marks[MARK_END]-marks[MARK_START], dev, flags); 154 155 return; 156 } 157 158 static void 159 boot(char *arg) 160 { 161 char filename[80]; 162 char *p; 163 int flags = 0; 164 165 if (*arg == 0 || *arg == '-') { 166 strcpy(filename, default_kernel); 167 if (*arg == '-') 168 if (parseopts(arg, &flags) == 0) { 169 help(); 170 return; 171 } 172 doboot(filename, flags); 173 return; 174 } else { 175 p = gettrailer(arg); 176 if (strchr(arg, ':')) { 177 strcpy(filename, arg); 178 if (arg[strlen(arg) - 1] == ':') 179 strcat(filename, "netbsd"); 180 } else { 181 strcpy(filename, default_kernel); 182 strcpy(strchr(filename, ':') + 1, arg); 183 } 184 if (*p == '-') { 185 if (parseopts(p, &flags) == 0) 186 return; 187 } else if (*p != 0) { 188 help(); 189 return; 190 } 191 192 doboot(filename, flags); 193 return; 194 } 195 } 196 197 static void 198 ls(char *arg) 199 { 200 char filename[80]; 201 202 devopen_open_dir = 1; 203 if (*arg == 0) { 204 strcpy(filename, default_kernel); 205 strcpy(strchr(filename, ':')+1, "/"); 206 } else if (strchr(arg, ':') == 0) { 207 strcpy(filename, default_kernel); 208 strcpy(strchr(filename, ':')+1, arg); 209 } else { 210 strcpy(filename, arg); 211 if (*(strchr(arg, ':')+1) == 0) 212 strcat(filename, "/"); 213 } 214 ufs_ls(filename); 215 devopen_open_dir = 0; 216 } 217 218 int 219 bootmenu(void) 220 { 221 char input[80]; 222 int n = 5, c; 223 224 printf("Press return to boot now, any other key for boot menu\n"); 225 printf("booting %s - starting in %d seconds. ", 226 default_kernel, n); 227 while (n-- > 0 && (c = awaitkey_1sec()) == 0) { 228 printf("\r"); 229 printf("booting %s - starting in %d seconds. ", 230 default_kernel, n); 231 } 232 printf("\r"); 233 printf("booting %s - starting in %d seconds. ", default_kernel, 0); 234 printf("\n"); 235 236 if (c == 0 || c == '\r') { 237 doboot(default_kernel, 0); 238 printf("Could not start %s; ", default_kernel); 239 strcat(default_kernel, ".gz"); 240 printf("trying %s.\n", default_kernel); 241 doboot(default_kernel, 0); 242 printf("Could not start %s; ", default_kernel); 243 } 244 245 printf("Please use the absolute unit# (e.g. SCSI ID)" 246 " instead of the NetBSD logical #.\n"); 247 for (;;) { 248 char *p, *options; 249 250 printf("> "); 251 gets(input); 252 253 for (p = &input[0]; p - &input[0] < 80 && *p == ' '; p++); 254 options = gettrailer(p); 255 if (strcmp("boot", p) == 0) 256 boot(options); 257 else if (strcmp("help", p) == 0 || 258 strcmp("?", p) == 0) 259 help(); 260 else if ((strcmp("halt", p) == 0) ||(strcmp("reboot", p) == 0)) 261 exit(0); 262 else if (strcmp("ls", p) == 0) 263 ls(options); 264 else 265 printf("Unknown command %s\n", p); 266 } 267 } 268 269 270 extern const char bootprog_rev[]; 271 extern const char bootprog_name[]; 272 extern const char bootprog_date[]; 273 extern const char bootprog_maker[]; 274 275 /* 276 * Arguments from the boot block: 277 * bootdev - specifies the device from which /boot was read, in 278 * bootdev format. 279 */ 280 void 281 bootmain(int bootdev) 282 { 283 hostadaptor = get_scsi_host_adapter(); 284 mpu = detectmpu(); 285 286 if (mpu < 3) { /* not tested on 68020 */ 287 printf("This MPU cannot run NetBSD.\n"); 288 exit(1); 289 } 290 if (SRAM_MEMSIZE < 4*1024*1024) { 291 printf("Main memory too small.\n"); 292 exit(1); 293 } 294 295 console_device = consio_init(console_device); 296 setheap(HEAP_START, HEAP_END); 297 298 switch (B_TYPE(bootdev)) { 299 case X68K_MAJOR_FD: 300 default_kernel[0] = 'f'; 301 default_kernel[2] = '0' + B_UNIT(bootdev); 302 default_kernel[3] = 'a'; 303 break; 304 case X68K_MAJOR_SD: 305 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 306 default_kernel[3] = 307 'a' + sd_getbsdpartition(B_X68K_SCSI_ID(bootdev), 308 B_X68K_SCSI_PART(bootdev)); 309 break; 310 case X68K_MAJOR_CD: 311 default_kernel[0] = 'c'; 312 default_kernel[2] = '0' + B_X68K_SCSI_ID(bootdev); 313 default_kernel[3] = 'a'; 314 break; 315 default: 316 printf("Warning: unknown boot device: %x\n", bootdev); 317 } 318 print_title("%s, Revision %s\n\t(%s, %s)", 319 bootprog_name, bootprog_rev, 320 bootprog_maker, bootprog_date); 321 bootmenu(); 322 } 323