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