1 /* $NetBSD: boot2.c,v 1.5 2004/11/25 08:30:52 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 int errno; 60 extern int boot_biosdev; 61 extern int boot_biossector; /* may be wrong... */ 62 63 extern struct x86_boot_params boot_params; 64 65 extern const char bootprog_name[], bootprog_rev[], bootprog_date[], 66 bootprog_maker[]; 67 68 static const char * const names[][2] = { 69 { "netbsd", "netbsd.gz" }, 70 { "netbsd.old", "netbsd.old.gz" }, 71 { "onetbsd", "onetbsd.gz" }, 72 #ifdef notyet 73 { "netbsd.el", "netbsd.el.gz" }, 74 #endif /*notyet*/ 75 }; 76 77 #define NUMNAMES (sizeof(names)/sizeof(names[0])) 78 #define DEFFILENAME names[0][0] 79 80 #define MAXDEVNAME 16 81 82 static char *default_devname; 83 static int default_unit, default_partition; 84 static const char *default_filename; 85 86 char *sprint_bootsel(const char *); 87 void bootit(const char *, int, int); 88 void print_banner(void); 89 void boot2(uint32_t, uint32_t); 90 91 void command_help(char *); 92 void command_ls(char *); 93 void command_quit(char *); 94 void command_boot(char *); 95 void command_dev(char *); 96 void command_consdev(char *); 97 98 const struct bootblk_command commands[] = { 99 { "help", command_help }, 100 { "?", command_help }, 101 { "ls", command_ls }, 102 { "quit", command_quit }, 103 { "boot", command_boot }, 104 { "dev", command_dev }, 105 { "consdev", command_consdev }, 106 { NULL, NULL }, 107 }; 108 109 int 110 parsebootfile(const char *fname, char **fsname, char **devname, 111 u_int *unit, u_int *partition, const char **file) 112 { 113 const char *col; 114 115 *fsname = "ufs"; 116 *devname = default_devname; 117 *unit = default_unit; 118 *partition = default_partition; 119 *file = default_filename; 120 121 if (fname == NULL) 122 return(0); 123 124 if((col = strchr(fname, ':'))) { /* device given */ 125 static char savedevname[MAXDEVNAME+1]; 126 int devlen; 127 unsigned int u = 0, p = 0; 128 int i = 0; 129 130 devlen = col - fname; 131 if (devlen > MAXDEVNAME) 132 return(EINVAL); 133 134 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 135 if (!isvalidname(fname[i])) 136 return(EINVAL); 137 do { 138 savedevname[i] = fname[i]; 139 i++; 140 } while (isvalidname(fname[i])); 141 savedevname[i] = '\0'; 142 143 #define isnum(c) ((c) >= '0' && (c) <= '9') 144 if (i < devlen) { 145 if (!isnum(fname[i])) 146 return(EUNIT); 147 do { 148 u *= 10; 149 u += fname[i++] - '0'; 150 } while (isnum(fname[i])); 151 } 152 153 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 154 if (i < devlen) { 155 if (!isvalidpart(fname[i])) 156 return(EPART); 157 p = fname[i++] - 'a'; 158 } 159 160 if (i != devlen) 161 return(ENXIO); 162 163 *devname = savedevname; 164 *unit = u; 165 *partition = p; 166 fname = col + 1; 167 } 168 169 if (*fname) 170 *file = fname; 171 172 return(0); 173 } 174 175 char * 176 sprint_bootsel(const char *filename) 177 { 178 char *fsname, *devname; 179 int unit, partition; 180 const char *file; 181 static char buf[80]; 182 183 if (parsebootfile(filename, &fsname, &devname, &unit, 184 &partition, &file) == 0) { 185 sprintf(buf, "%s%d%c:%s", devname, unit, 'a' + partition, file); 186 return(buf); 187 } 188 return("(invalid)"); 189 } 190 191 void 192 bootit(const char *filename, int howto, int tell) 193 { 194 195 if (tell) { 196 printf("booting %s", sprint_bootsel(filename)); 197 if (howto) 198 printf(" (howto 0x%x)", howto); 199 printf("\n"); 200 } 201 202 if (exec_netbsd(filename, 0, howto) < 0) 203 printf("boot: %s: %s\n", sprint_bootsel(filename), 204 strerror(errno)); 205 else 206 printf("boot returned\n"); 207 } 208 209 void 210 print_banner(void) 211 { 212 213 printf("\n"); 214 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 215 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 216 printf(">> Memory: %d/%d k\n", getbasemem(), getextmem()); 217 } 218 219 220 void 221 boot2(uint32_t boot_biosdev, uint32_t boot_biossector) 222 { 223 int currname; 224 char c; 225 226 initio(boot_params.bp_consdev); 227 228 #ifdef SUPPORT_PS2 229 biosmca(); 230 #endif 231 gateA20(); 232 233 if (boot_params.bp_flags & X86_BP_FLAGS_RESET_VIDEO) 234 biosvideomode(); 235 236 print_banner(); 237 238 /* try to set default device to what BIOS tells us */ 239 bios2dev(boot_biosdev, &default_devname, &default_unit, 240 boot_biossector, &default_partition); 241 242 /* if the user types "boot" without filename */ 243 default_filename = DEFFILENAME; 244 245 printf("Press return to boot now, any other key for boot menu\n"); 246 currname = 0; 247 for (;;) { 248 printf("booting %s - starting in ", 249 sprint_bootsel(names[currname][0])); 250 251 c = awaitkey(boot_params.bp_timeout, 1); 252 if ((c != '\r') && (c != '\n') && (c != '\0') && 253 ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 254 || check_password(boot_params.bp_password))) { 255 printf("type \"?\" or \"help\" for help.\n"); 256 bootmenu(); /* does not return */ 257 } 258 259 /* 260 * try pairs of names[] entries, foo and foo.gz 261 */ 262 /* don't print "booting..." again */ 263 bootit(names[currname][0], 0, 0); 264 /* since it failed, try compressed bootfile. */ 265 bootit(names[currname][1], 0, 1); 266 /* since it failed, try switching bootfile. */ 267 currname = (currname + 1) % NUMNAMES; 268 } 269 } 270 271 /* ARGSUSED */ 272 void 273 command_help(char *arg) 274 { 275 276 printf("commands are:\n" 277 "boot [xdNx:][filename] [-acdqsv]\n" 278 " (ex. \"hd0a:netbsd.old -s\"\n" 279 "ls [path]\n" 280 "dev xd[N[x]]:\n" 281 "consdev {pc|com[0123]|com[0123]kbd|auto}\n" 282 "help|?\n" 283 "quit\n"); 284 } 285 286 void 287 command_ls(char *arg) 288 { 289 const char *save = default_filename; 290 291 default_filename = "/"; 292 ufs_ls(arg); 293 default_filename = save; 294 } 295 296 /* ARGSUSED */ 297 void 298 command_quit(char *arg) 299 { 300 301 printf("Exiting...\n"); 302 delay(1000000); 303 reboot(); 304 /* Note: we shouldn't get to this point! */ 305 panic("Could not reboot!"); 306 exit(0); 307 } 308 309 void 310 command_boot(char *arg) 311 { 312 char *filename; 313 int howto; 314 315 if (parseboot(arg, &filename, &howto)) 316 bootit(filename, howto, 1); 317 } 318 319 void 320 command_dev(char *arg) 321 { 322 static char savedevname[MAXDEVNAME + 1]; 323 char *fsname, *devname; 324 const char *file; /* dummy */ 325 326 if (*arg == '\0') { 327 printf("%s%d%c:\n", default_devname, default_unit, 328 'a' + default_partition); 329 return; 330 } 331 332 if (!strchr(arg, ':') || 333 parsebootfile(arg, &fsname, &devname, &default_unit, 334 &default_partition, &file)) { 335 command_help(NULL); 336 return; 337 } 338 339 /* put to own static storage */ 340 strncpy(savedevname, devname, MAXDEVNAME + 1); 341 default_devname = savedevname; 342 } 343 344 static const struct cons_devs { 345 const char *name; 346 u_int tag; 347 } cons_devs[] = { 348 { "pc", CONSDEV_PC }, 349 { "com0", CONSDEV_COM0 }, 350 { "com1", CONSDEV_COM1 }, 351 { "com2", CONSDEV_COM2 }, 352 { "com3", CONSDEV_COM3 }, 353 { "com0kbd", CONSDEV_COM0KBD }, 354 { "com1kbd", CONSDEV_COM1KBD }, 355 { "com2kbd", CONSDEV_COM2KBD }, 356 { "com3kbd", CONSDEV_COM3KBD }, 357 { "auto", CONSDEV_AUTO }, 358 { 0, 0 } }; 359 360 void 361 command_consdev(char *arg) 362 { 363 const struct cons_devs *cdp; 364 365 for (cdp = cons_devs; cdp->name; cdp++) { 366 if (!strcmp(arg, cdp->name)) { 367 initio(cdp->tag); 368 print_banner(); 369 return; 370 } 371 } 372 printf("invalid console device.\n"); 373 } 374