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