1 /* $NetBSD: boot2.c,v 1.12 2005/12/11 12:17:47 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2003 5 * David Laight. All rights reserved 6 * Copyright (c) 1996, 1997, 1999 7 * Matthias Drochner. All rights reserved. 8 * Copyright (c) 1996, 1997 9 * Perry E. Metzger. All rights reserved. 10 * Copyright (c) 1997 11 * Jason R. Thorpe. All rights reserved 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgements: 23 * This product includes software developed for the NetBSD Project 24 * by Matthias Drochner. 25 * This product includes software developed for the NetBSD Project 26 * by Perry E. Metzger. 27 * 4. The names of the authors may not be used to endorse or promote products 28 * derived from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 33 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 39 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42 /* Based on stand/biosboot/main.c */ 43 44 #include <sys/types.h> 45 #include <sys/reboot.h> 46 #include <sys/bootblock.h> 47 48 #include <lib/libsa/stand.h> 49 #include <lib/libsa/ufs.h> 50 #include <lib/libkern/libkern.h> 51 52 #include <libi386.h> 53 #include "devopen.h" 54 55 #ifdef SUPPORT_PS2 56 #include <biosmca.h> 57 #endif 58 59 extern struct x86_boot_params boot_params; 60 61 extern const char bootprog_name[], bootprog_rev[], bootprog_date[], 62 bootprog_maker[]; 63 64 int errno; 65 66 int boot_biosdev; 67 u_int boot_biossector; 68 69 static const char * const names[][2] = { 70 { "netbsd", "netbsd.gz" }, 71 { "onetbsd", "onetbsd.gz" }, 72 { "netbsd.old", "netbsd.old.gz" }, 73 }; 74 75 #define NUMNAMES (sizeof(names)/sizeof(names[0])) 76 #define DEFFILENAME names[0][0] 77 78 #define MAXDEVNAME 16 79 80 static char *default_devname; 81 static int default_unit, default_partition; 82 static const char *default_filename; 83 84 char *sprint_bootsel(const char *); 85 void bootit(const char *, int, int); 86 void print_banner(void); 87 void boot2(int, u_int); 88 89 void command_help(char *); 90 void command_ls(char *); 91 void command_quit(char *); 92 void command_boot(char *); 93 void command_dev(char *); 94 void command_consdev(char *); 95 96 const struct bootblk_command commands[] = { 97 { "help", command_help }, 98 { "?", command_help }, 99 { "ls", command_ls }, 100 { "quit", command_quit }, 101 { "boot", command_boot }, 102 { "dev", command_dev }, 103 { "consdev", command_consdev }, 104 { NULL, NULL }, 105 }; 106 107 int 108 parsebootfile(const char *fname, char **fsname, char **devname, 109 int *unit, int *partition, const char **file) 110 { 111 const char *col; 112 113 *fsname = "ufs"; 114 *devname = default_devname; 115 *unit = default_unit; 116 *partition = default_partition; 117 *file = default_filename; 118 119 if (fname == NULL) 120 return 0; 121 122 if ((col = strchr(fname, ':')) != NULL) { /* device given */ 123 static char savedevname[MAXDEVNAME+1]; 124 int devlen; 125 int u = 0, p = 0; 126 int i = 0; 127 128 devlen = col - fname; 129 if (devlen > MAXDEVNAME) 130 return EINVAL; 131 132 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 133 if (!isvalidname(fname[i])) 134 return EINVAL; 135 do { 136 savedevname[i] = fname[i]; 137 i++; 138 } while (isvalidname(fname[i])); 139 savedevname[i] = '\0'; 140 141 #define isnum(c) ((c) >= '0' && (c) <= '9') 142 if (i < devlen) { 143 if (!isnum(fname[i])) 144 return EUNIT; 145 do { 146 u *= 10; 147 u += fname[i++] - '0'; 148 } while (isnum(fname[i])); 149 } 150 151 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 152 if (i < devlen) { 153 if (!isvalidpart(fname[i])) 154 return EPART; 155 p = fname[i++] - 'a'; 156 } 157 158 if (i != devlen) 159 return ENXIO; 160 161 *devname = savedevname; 162 *unit = u; 163 *partition = p; 164 fname = col + 1; 165 } 166 167 if (*fname) 168 *file = fname; 169 170 return 0; 171 } 172 173 char * 174 sprint_bootsel(const char *filename) 175 { 176 char *fsname, *devname; 177 int unit, partition; 178 const char *file; 179 static char buf[80]; 180 181 if (parsebootfile(filename, &fsname, &devname, &unit, 182 &partition, &file) == 0) { 183 sprintf(buf, "%s%d%c:%s", devname, unit, 'a' + partition, file); 184 return buf; 185 } 186 return "(invalid)"; 187 } 188 189 void 190 bootit(const char *filename, int howto, int tell) 191 { 192 193 if (tell) { 194 printf("booting %s", sprint_bootsel(filename)); 195 if (howto) 196 printf(" (howto 0x%x)", howto); 197 printf("\n"); 198 } 199 200 if (exec_netbsd(filename, 0, howto) < 0) 201 printf("boot: %s: %s\n", sprint_bootsel(filename), 202 strerror(errno)); 203 else 204 printf("boot returned\n"); 205 } 206 207 void 208 print_banner(void) 209 { 210 211 printf("\n"); 212 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 213 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 214 printf(">> Memory: %d/%d k\n", getbasemem(), getextmem()); 215 } 216 217 /* 218 * Called from the initial entry point boot_start in biosboot.S 219 * 220 * biosdev: BIOS drive number the system booted from 221 * biossector: Sector number of the NetBSD partition 222 */ 223 void 224 boot2(int biosdev, u_int biossector) 225 { 226 int currname; 227 char c; 228 229 initio(boot_params.bp_consdev); 230 231 #ifdef SUPPORT_PS2 232 biosmca(); 233 #endif 234 gateA20(); 235 236 if (boot_params.bp_flags & X86_BP_FLAGS_RESET_VIDEO) 237 biosvideomode(); 238 239 print_banner(); 240 241 /* need to remember these */ 242 boot_biosdev = biosdev; 243 boot_biossector = biossector; 244 245 /* try to set default device to what BIOS tells us */ 246 bios2dev(biosdev, biossector, &default_devname, &default_unit, 247 &default_partition); 248 249 /* if the user types "boot" without filename */ 250 default_filename = DEFFILENAME; 251 252 printf("Press return to boot now, any other key for boot menu\n"); 253 for (currname = 0; currname < NUMNAMES; currname++) { 254 printf("booting %s - starting in ", 255 sprint_bootsel(names[currname][0])); 256 257 c = awaitkey(boot_params.bp_timeout, 1); 258 if ((c != '\r') && (c != '\n') && (c != '\0') && 259 ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 260 || check_password(boot_params.bp_password))) { 261 printf("type \"?\" or \"help\" for help.\n"); 262 bootmenu(); /* does not return */ 263 } 264 265 /* 266 * try pairs of names[] entries, foo and foo.gz 267 */ 268 /* don't print "booting..." again */ 269 bootit(names[currname][0], 0, 0); 270 /* since it failed, try compressed bootfile. */ 271 bootit(names[currname][1], 0, 1); 272 } 273 274 bootmenu(); /* does not return */ 275 } 276 277 /* ARGSUSED */ 278 void 279 command_help(char *arg) 280 { 281 282 printf("commands are:\n" 283 "boot [xdNx:][filename] [-acdqsv]\n" 284 " (ex. \"hd0a:netbsd.old -s\"\n" 285 "ls [path]\n" 286 "dev xd[N[x]]:\n" 287 "consdev {pc|com[0123]|com[0123]kbd|auto}\n" 288 "help|?\n" 289 "quit\n"); 290 } 291 292 void 293 command_ls(char *arg) 294 { 295 const char *save = default_filename; 296 297 default_filename = "/"; 298 ufs_ls(arg); 299 default_filename = save; 300 } 301 302 /* ARGSUSED */ 303 void 304 command_quit(char *arg) 305 { 306 307 printf("Exiting...\n"); 308 delay(1000000); 309 reboot(); 310 /* Note: we shouldn't get to this point! */ 311 panic("Could not reboot!"); 312 exit(0); 313 } 314 315 void 316 command_boot(char *arg) 317 { 318 char *filename; 319 int howto; 320 321 if (parseboot(arg, &filename, &howto)) 322 bootit(filename, howto, 1); 323 } 324 325 void 326 command_dev(char *arg) 327 { 328 static char savedevname[MAXDEVNAME + 1]; 329 char *fsname, *devname; 330 const char *file; /* dummy */ 331 332 if (*arg == '\0') { 333 printf("%s%d%c:\n", default_devname, default_unit, 334 'a' + default_partition); 335 return; 336 } 337 338 if (strchr(arg, ':') != NULL || 339 parsebootfile(arg, &fsname, &devname, &default_unit, 340 &default_partition, &file)) { 341 command_help(NULL); 342 return; 343 } 344 345 /* put to own static storage */ 346 strncpy(savedevname, devname, MAXDEVNAME + 1); 347 default_devname = savedevname; 348 } 349 350 static const struct cons_devs { 351 const char *name; 352 u_int tag; 353 } cons_devs[] = { 354 { "pc", CONSDEV_PC }, 355 { "com0", CONSDEV_COM0 }, 356 { "com1", CONSDEV_COM1 }, 357 { "com2", CONSDEV_COM2 }, 358 { "com3", CONSDEV_COM3 }, 359 { "com0kbd", CONSDEV_COM0KBD }, 360 { "com1kbd", CONSDEV_COM1KBD }, 361 { "com2kbd", CONSDEV_COM2KBD }, 362 { "com3kbd", CONSDEV_COM3KBD }, 363 { "auto", CONSDEV_AUTO }, 364 { NULL, 0 } 365 }; 366 367 void 368 command_consdev(char *arg) 369 { 370 const struct cons_devs *cdp; 371 372 for (cdp = cons_devs; cdp->name; cdp++) { 373 if (strcmp(arg, cdp->name) == 0) { 374 initio(cdp->tag); 375 print_banner(); 376 return; 377 } 378 } 379 printf("invalid console device.\n"); 380 } 381