/* $NetBSD: boot2.c,v 1.2.8.1 2012/02/18 07:32:27 mrg Exp $ */ /* * Copyright (c) 2003 * David Laight. All rights reserved * Copyright (c) 1996, 1997, 1999 * Matthias Drochner. All rights reserved. * Copyright (c) 1996, 1997 * Perry E. Metzger. All rights reserved. * Copyright (c) 1997 * Jason R. Thorpe. All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgements: * This product includes software developed for the NetBSD Project * by Matthias Drochner. * This product includes software developed for the NetBSD Project * by Perry E. Metzger. * 4. The names of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Based on stand/biosboot/main.c */ #include #include #include #include #include #include #include #include #include "biosdisk.h" #include "boot.h" #include "bootinfo.h" #include "cons.h" int errno; extern struct landisk_boot_params boot_params; static const char * const names[][2] = { { "netbsd", "netbsd.gz" }, { "netbsd.old", "netbsd.old.gz", }, { "onetbsd", "onetbsd.gz" }, }; #define NUMNAMES (sizeof(names) / sizeof(names[0])) #define DEFFILENAME names[0][0] #define MAXDEVNAME 16 static char *default_devname; static uint default_unit, default_partition; static const char *default_filename; char *sprint_bootsel(const char *filename); void bootit(const char *filename, int howto, int tell); void print_banner(void); void boot2(uint32_t boot_biossector); int exec_netbsd(const char *file, int howto); static char *gettrailer(char *arg); static int parseopts(const char *opts, int *howto); static int parseboot(char *arg, char **filename, int *howto); void bootmenu(void); static void bootcmd_help(char *); static void bootcmd_ls(char *); static void bootcmd_quit(char *); static void bootcmd_halt(char *); static void bootcmd_boot(char *); static void bootcmd_monitor(char *); static const struct bootblk_command { const char *c_name; void (*c_fn)(char *arg); } bootcmds[] = { { "help", bootcmd_help }, { "?", bootcmd_help }, { "ls", bootcmd_ls }, { "quit", bootcmd_quit }, { "halt", bootcmd_halt }, { "boot", bootcmd_boot }, { "!", bootcmd_monitor }, { NULL, NULL }, }; int parsebootfile(const char *fname, char **devname, uint *unit, uint *partition, const char **file) { const char *col; *devname = default_devname; *unit = default_unit; *partition = default_partition; *file = default_filename; if (fname == NULL) return (0); if((col = strchr(fname, ':'))) { /* device given */ static char savedevname[MAXDEVNAME+1]; int devlen; unsigned int u = 0, p = 0; int i = 0; devlen = col - fname; if (devlen > MAXDEVNAME) return (EINVAL); #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') if (!isvalidname(fname[i])) return (EINVAL); do { savedevname[i] = fname[i]; i++; } while (isvalidname(fname[i])); savedevname[i] = '\0'; #define isnum(c) ((c) >= '0' && (c) <= '9') if (i < devlen) { if (!isnum(fname[i])) return (EUNIT); do { u *= 10; u += fname[i++] - '0'; } while (isnum(fname[i])); } #define isvalidpart(c) ((c) >= 'a' && (c) <= 'p') if (i < devlen) { if (!isvalidpart(fname[i])) return (EPART); p = fname[i++] - 'a'; } if (i != devlen) return (ENXIO); *devname = savedevname; *unit = u; *partition = p; fname = col + 1; } if (*fname) *file = fname; return (0); } char * sprint_bootsel(const char *filename) { static char buf[80]; char *devname; uint unit, partition; const char *file; if (parsebootfile(filename, &devname, &unit, &partition, &file) == 0) { sprintf(buf, "%s%d%c:%s", devname, unit, 'a' + partition, file); return (buf); } return ("(invalid)"); } void bootit(const char *filename, int howto, int tell) { if (tell) { printf("booting %s", sprint_bootsel(filename)); if (howto) printf(" (howto 0x%x)", howto); printf("\n"); } if (exec_netbsd(filename, howto) < 0) { printf("boot: %s: %s\n", sprint_bootsel(filename), strerror(errno)); } else { printf("boot returned\n"); } } void print_banner(void) { extern const char bootprog_name[]; extern const char bootprog_rev[]; printf("\n"); printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); } void boot2(uint32_t boot_biossector) { int currname; int c; /* Initialize hardware */ tick_init(); /* Initialize console */ cninit(boot_params.bp_consdev); print_banner(); /* try to set default device to what BIOS tells us */ bios2dev(0x40, &default_devname, &default_unit, boot_biossector, &default_partition); /* if the user types "boot" without filename */ default_filename = DEFFILENAME; printf("Press return to boot now, any other key for boot menu\n"); currname = 0; for (;;) { printf("booting %s - starting in ", sprint_bootsel(names[currname][0])); c = awaitkey(boot_params.bp_timeout, 1); if ((c != '\r') && (c != '\n') && (c != '\0')) { printf("type \"?\" or \"help\" for help.\n"); bootmenu(); /* does not return */ } /* * try pairs of names[] entries, foo and foo.gz */ /* don't print "booting..." again */ bootit(names[currname][0], 0, 0); /* since it failed, try compressed bootfile. */ bootit(names[currname][1], 0, 1); /* since it failed, try switching bootfile. */ currname = (currname + 1) % NUMNAMES; } } int exec_netbsd(const char *file, int howto) { static char bibuf[BOOTINFO_MAXSIZE]; u_long marks[MARK_MAX]; int fd; BI_ALLOC(6); /* XXX */ marks[MARK_START] = 0; /* loadaddr */ if ((fd = loadfile(file, marks, LOAD_KERNEL)) == -1) goto out; printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY], marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]); { struct btinfo_common *help; char *p; int i; p = bibuf; memcpy(p, &bootinfo->nentries, sizeof(bootinfo->nentries)); p += sizeof(bootinfo->nentries); for (i = 0; i < bootinfo->nentries; i++) { help = (struct btinfo_common *)(bootinfo->entry[i]); memcpy(p, help, help->len); p += help->len; } } cache_flush(); cache_disable(); (*(void (*)(int, void *))marks[MARK_ENTRY])(howto, bibuf); panic("exec returned"); out: BI_FREE(); bootinfo = 0; return (-1); } /* * boot menu */ /* ARGSUSED */ static void bootcmd_help(char *arg) { printf("commands are:\n" "boot [xdNx:][filename] [-acdqsv]\n" " (ex. \"hd0a:netbsd.old -s\"\n" "ls [path]\n" "help|?\n" "halt\n" "quit\n"); } static void bootcmd_ls(char *arg) { const char *save = default_filename; default_filename = "/"; ls(arg); default_filename = save; } /* ARGSUSED */ static void bootcmd_quit(char *arg) { printf("Exiting...\n"); delay(1000); reboot(); /* Note: we shouldn't get to this point! */ panic("Could not reboot!"); exit(0); } /* ARGSUSED */ static void bootcmd_halt(char *arg) { printf("Exiting...\n"); delay(1000); halt(); /* Note: we shouldn't get to this point! */ panic("Could not halt!"); exit(0); } static void bootcmd_boot(char *arg) { char *filename; int howto; if (parseboot(arg, &filename, &howto)) { bootit(filename, howto, 1); } } /* ARGSUSED */ static void bootcmd_monitor(char *arg) { db_monitor(); printf("\n"); } static void docommand(const struct bootblk_command * const cmds, char *arg) { char *options; int i; options = gettrailer(arg); for (i = 0; cmds[i].c_name != NULL; i++) { if (strcmp(arg, cmds[i].c_name) == 0) { (*cmds[i].c_fn)(options); return; } } printf("unknown command\n"); bootcmd_help(NULL); } void bootmenu(void) { char input[256]; char *c; for (;;) { c = input; input[0] = '\0'; printf("> "); gets(input); /* * Skip leading whitespace. */ while (*c == ' ') { c++; } if (*c != '\0') { docommand(bootcmds, c); } } } /* * from arch/i386/stand/lib/parseutil.c */ /* * chops the head from the arguments and returns the arguments if any, * or possibly an empty string. */ static char * gettrailer(char *arg) { char *options; if ((options = strchr(arg, ' ')) == NULL) return (""); else *options++ = '\0'; /* trim leading blanks */ while (*options && *options == ' ') options++; return (options); } static int parseopts(const char *opts, int *howto) { int r, tmpopt = 0; opts++; /* skip - */ while (*opts && *opts != ' ') { r = 0; BOOT_FLAG(*opts, r); if (r == 0) { printf("-%c: unknown flag\n", *opts); bootcmd_help(NULL); return (0); } tmpopt |= r; opts++; } *howto = tmpopt; return (1); } static int parseboot(char *arg, char **filename, int *howto) { char *opts = NULL; *filename = 0; *howto = 0; /* if there were no arguments */ if (*arg == NULL) return (1); /* format is... */ /* [[xxNx:]filename] [-adqsv] */ /* check for just args */ if (arg[0] == '-') { opts = arg; } else { /* there's a file name */ *filename = arg; opts = gettrailer(arg); if (*opts == NULL) { opts = NULL; } else if (*opts != '-') { printf("invalid arguments\n"); bootcmd_help(NULL); return (0); } } /* at this point, we have dealt with filenames. */ /* now, deal with options */ if (opts) { if (parseopts(opts, howto) == 0) { return (0); } } return (1); } /* * for common/lib/libc/arch/sh3/gen/udivsi3.S */ int raise(int sig); /*ARGSUSED*/ int raise(int sig) { return 0; }