Subject: Adding a prompt to bootloader to specify kernel name
To: None <port-cobalt@NetBSD.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-cobalt
Date: 04/03/2004 20:54:03
Today I modify bootloader in cobalt/stand/boot to add a prompt
to specify a kernel filename to be loaded. This makes it easier
to recover system when newer kernel does not boot.
I've put boot.gz binary at:
http://www.ceres.dti.ne.jp/~tsutsui/netbsd/boot-cobalt-20040403.gz
and source diff is attached.
Some of these code might need enhancement and bootinfo structures
in a kernel should also be reorganized, but I think still it useful
for now.
Comments?
---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp
Index: stand/boot/Makefile
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/Makefile,v
retrieving revision 1.6
diff -u -r1.6 Makefile
--- stand/boot/Makefile 27 Jan 2004 21:03:18 -0000 1.6
+++ stand/boot/Makefile 3 Apr 2004 00:05:36 -0000
@@ -68,7 +68,7 @@
PROG= boot
# common sources
SRCS+= start.S boot.c devopen.c conf.c clock.c bootinfo.c
-SRCS+= prf.c com.c cons.c ns16550.c pciide.c wdc.c wd.c
+SRCS+= prf.c com.c cons.c ns16550.c pciide.c tgets.c wdc.c wd.c
SRCS+= vers.c
CLEANFILES+= vers.c
Index: stand/boot/boot.c
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/boot.c,v
retrieving revision 1.3
diff -u -r1.3 boot.c
--- stand/boot/boot.c 7 Jan 2004 12:43:44 -0000 1.3
+++ stand/boot/boot.c 3 Apr 2004 00:05:36 -0000
@@ -79,6 +79,7 @@
#include <lib/libkern/libkern.h>
#include <sys/param.h>
+#include <sys/boot_flag.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
@@ -88,18 +89,18 @@
#include "bootinfo.h"
char *kernelnames[] = {
- "netbsd",
- "netbsd.gz",
- "onetbsd",
- "onetbsd.gz",
- "netbsd.bak",
- "netbsd.bak.gz",
- "netbsd.old",
- "netbsd.old.gz",
- "netbsd.cobalt",
- "netbsd.cobalt.gz",
- "netbsd.elf",
- "netbsd.elf.gz",
+ "/netbsd",
+ "/netbsd.gz",
+ "/onetbsd",
+ "/onetbsd.gz",
+ "/netbsd.bak",
+ "/netbsd.bak.gz",
+ "/netbsd.old",
+ "/netbsd.old.gz",
+ "/netbsd.cobalt",
+ "/netbsd.cobalt.gz",
+ "/netbsd.elf",
+ "/netbsd.elf.gz",
NULL
};
@@ -108,14 +109,15 @@
static char *bootstring;
-static int patch_bootstring (char *bootspec);
-static int get_bsdbootname (char **dev, char **name, char **kname);
-static int prominit (unsigned int memsize);
-static int print_banner (unsigned int memsize);
+static int patch_bootstring(char *);
+static int get_bsdbootname(char **, char **);
+static int parse_bootname(char *, int, char **, char **);
+static int prominit(unsigned int);
+static int print_banner(unsigned int);
int cpu_reboot(void);
-int main(unsigned int memsize);
+int main(unsigned int);
/*
* Perform CPU reboot.
@@ -123,6 +125,7 @@
int
cpu_reboot()
{
+
printf("rebooting...\n\n");
*(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET;
@@ -134,10 +137,11 @@
/*
* Substitute root value with NetBSD root partition name.
*/
-int
+static int
patch_bootstring(bootspec)
char *bootspec;
{
+
char *sp = bootstring;
u_int8_t unit, part;
int dev, error;
@@ -152,7 +156,7 @@
DPRINTF(("patch_bootstring: %d, %d\n", unit, part));
/* take out the 'root=xxx' parameter */
- if ( (sp = strstr(bootstring, "root=")) != NULL) {
+ if ((sp = strstr(bootstring, "root=")) != NULL) {
const char *end;
end = strchr(sp, ' ');
@@ -189,62 +193,130 @@
/*
* Extract NetBSD boot specification
*/
-int
-get_bsdbootname(dev, name, kname)
+static int
+get_bsdbootname(dev, kname)
char **dev;
- char **name;
char **kname;
{
- char *spec;
-
- *dev = NULL;
- *name = NULL;
- *kname = NULL;
-
- if ( (spec = strstr(bootstring, "nbsd=")) != NULL) {
- int len;
- char *ptr = strchr(spec, ' ');
-
+ int len, error;
+ char *bootstr_dev, *bootstr_kname;
+ char *prompt_dev, *prompt_kname;
+ char *ptr, *spec;
+ char c, namebuf[PATH_MAX];
+
+ bootstr_dev = prompt_dev = NULL;
+ bootstr_kname = prompt_kname = NULL;
+
+ /* first, get bootname from bootstrings */
+ if ((spec = strstr(bootstring, "nbsd=")) != NULL) {
+ ptr = strchr(spec, ' ');
spec += 5; /* skip 'nbsd=' */
len = (ptr == NULL) ? strlen(spec) : ptr - spec;
-
if (len > 0) {
- char *devname = alloc(len + 1);
- if (devname != NULL) {
- memcpy(devname, spec, len);
- devname[len] = '\0';
-
- if ( (ptr = memchr(devname,':',len)) != NULL) {
- /* wdXX:kernel */
- *ptr = '\0';
- *dev = devname;
-
- if (*++ptr)
- *kname = ptr;
-
- devname = alloc(len + 1);
- if (devname != NULL) {
- memcpy(devname, spec, len);
- devname[len] = '\0';
- }
- }
-
- *name = devname;
- return (0);
- }
+ if (parse_bootname(spec, len,
+ &bootstr_dev, &bootstr_kname))
+ return 1;
+ }
+ }
+
+ DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n",
+ bootstr_dev ? bootstr_dev : "<NULL>",
+ bootstr_kname ? bootstr_kname : "<NULL>"));
+
+ spec = NULL;
+ len = 0;
+
+ memset(namebuf, 0, sizeof namebuf);
+ printf("Boot [%s:%s]: ",
+ bootstr_dev ? bootstr_dev : DEFBOOTDEV,
+ bootstr_kname ? bootstr_kname : DEFKERNELNAME);
+
+ if (tgets(namebuf) == -1)
+ printf("\n");
+
+ ptr = namebuf;
+ while ((c = *ptr) != '\0') {
+ while (c == ' ')
+ c = *++ptr;
+ if (c == '\0')
+ break;
+ if (c == '-') {
+ while ((c = *++ptr) && c != ' ')
+ ;
+#if notyet
+ BOOT_FLAG(c, boothowto);
+#endif
+ } else {
+ spec = ptr;
+ while ((c = *++ptr) && c != ' ')
+ ;
+ if (c)
+ *ptr++ = '\0';
+ len = strlen(spec);
}
}
- return (1);
+ if (len > 0) {
+ if (parse_bootname(spec, len, &prompt_dev, &prompt_kname))
+ return 1;
+ }
+
+ DPRINTF(("prompt_dev = %s, prompt_kname = %s\n",
+ prompt_dev ? prompt_dev : "<NULL>",
+ prompt_kname ? prompt_kname : "<NULL>"));
+
+ if (prompt_dev)
+ *dev = prompt_dev;
+ else
+ *dev = bootstr_dev;
+
+ if (prompt_kname)
+ *kname = prompt_kname;
+ else
+ *kname = bootstr_kname;
+
+ DPRINTF(("dev = %s, kname = %s\n",
+ *dev ? *dev : "<NULL>",
+ *kname ? *kname : "<NULL>"));
+
+ return 0;
+}
+
+static int
+parse_bootname(spec, len, dev, kname)
+ char *spec;
+ int len;
+ char **dev;
+ char **kname;
+{
+ char *bootname, *ptr;
+
+ bootname = alloc(len + 1);
+ if (bootname == NULL)
+ return 1;
+ memcpy(bootname, spec, len);
+ bootname[len] = '\0';
+
+ if ((ptr = memchr(bootname, ':', len)) != NULL) {
+ /* "wdXX:kernel" */
+ *ptr = '\0';
+ *dev = bootname;
+ if (*++ptr)
+ *kname = ptr;
+ } else
+ /* "kernel" */
+ *kname = bootname;
+ return 0;
}
/*
* Get the bootstring from PROM.
*/
-int
+static int
prominit(memsize)
unsigned int memsize;
{
+
bootstring = (char *)(memsize - 512);
bootstring[511] = '\0';
}
@@ -252,10 +324,11 @@
/*
* Print boot message.
*/
-int
+static int
print_banner(memsize)
unsigned int memsize;
{
+
printf("\n");
printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n",
bootprog_name, bootprog_rev, (void*)&start);
@@ -272,18 +345,15 @@
main(memsize)
unsigned int memsize;
{
- char *name, **namep, *dev, *kernel, *spec, *bi_addr;
+ char **namep, *dev, *kernel, *bi_addr;
char bootpath[PATH_MAX];
- int win;
+ int win, addr, speed;
u_long marks[MARK_MAX];
void (*entry) __P((unsigned int, u_int, char*));
-
struct btinfo_flags bi_flags;
struct btinfo_symtab bi_syms;
struct btinfo_bootpath bi_bpath;
- int addr, speed;
-
/* Initialize boot info early */
bi_flags.bi_flags = 0x0;
bi_addr = bi_init();
@@ -295,31 +365,30 @@
print_banner(memsize);
memset(marks, 0, sizeof marks);
- get_bsdbootname(&dev, &name, &kernel);
+ get_bsdbootname(&dev, &kernel);
if (kernel != NULL) {
DPRINTF(("kernel: %s\n", kernel));
- patch_bootstring(name);
- win = (loadfile(name, marks, LOAD_KERNEL) == 0);
+ kernelnames[0] = kernel;
+ kernelnames[1] = NULL;
} else {
- win = 0;
DPRINTF(("kernel: NULL\n"));
- DPRINTF(("Kernel names: %p\n", kernelnames));
- for (namep = kernelnames, win = 0;
- (*namep != NULL) && !win;
- namep++) {
- kernel = *namep;
-
- bootpath[0] = '\0';
-
- strcpy(bootpath, (dev != NULL) ? dev : "wd0a");
- strcat(bootpath, ":");
- strcat(bootpath, kernel);
-
- printf("Loading: %s\n", bootpath);
- patch_bootstring(bootpath);
- win = (loadfile(bootpath, marks, LOAD_ALL) != -1);
- }
+ }
+
+ win = 0;
+ DPRINTF(("Kernel names: %p\n", kernelnames));
+ for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) {
+ kernel = *namep;
+
+ bootpath[0] = '\0';
+
+ strcpy(bootpath, dev ? dev : DEFBOOTDEV);
+ strcat(bootpath, ":");
+ strcat(bootpath, kernel);
+
+ printf("Loading: %s\n", bootpath);
+ patch_bootstring(bootpath);
+ win = (loadfile(bootpath, marks, LOAD_ALL) != -1);
}
if (win) {
Index: stand/boot/boot.h
===================================================================
RCS file: /cvsroot/src/sys/arch/cobalt/stand/boot/boot.h,v
retrieving revision 1.1
diff -u -r1.1 boot.h
--- stand/boot/boot.h 25 Jun 2003 17:24:22 -0000 1.1
+++ stand/boot/boot.h 3 Apr 2004 00:05:36 -0000
@@ -40,6 +40,7 @@
#endif
#define MAXDEVNAME 16
+#define DEFBOOTDEV "wd0a"
#define DEFKERNELNAME kernelnames[0]
extern char *kernelnames[];
@@ -74,3 +75,5 @@
*/
int devparse (const char *fname, int *dev, u_int8_t *unit,
u_int8_t *part, const char **file);
+
+int tgets(char *);
--- /dev/null 2004-04-03 08:30:18.000000000 +0900
+++ stand/boot/tgets.c 2004-01-11 13:31:09.000000000 +0900
@@ -0,0 +1,95 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. 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. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)gets.c 8.1 (Berkeley) 6/11/93
+ */
+
+#include <lib/libsa/stand.h>
+#include "boot.h"
+
+#define USE_SCAN
+
+int
+tgets(buf)
+ char *buf;
+{
+ int c;
+ char *lp;
+
+#ifdef USE_SCAN
+ int i;
+
+#define SCANWAIT 10000
+#define PWAIT 500
+ for (i = 0; i < PWAIT; i++) {
+ if ((c = cnscan()) != -1)
+ goto next;
+ delay(SCANWAIT / 32); /* XXX */
+ }
+ return (-1);
+next:
+#else
+ c = getchar();
+#endif
+ for (lp = buf;; c = getchar()) {
+ switch (c & 0177) {
+ case '\n':
+ case '\r':
+ *lp = '\0';
+ putchar('\n');
+ return 0;
+ case '\b':
+ case '\177':
+ if (lp > buf) {
+ lp--;
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ }
+ break;
+ case 'r'&037: {
+ register char *p;
+
+ putchar('\n');
+ for (p = buf; p < lp; ++p)
+ putchar(*p);
+ break;
+ }
+ case 'u'&037:
+ case 'w'&037:
+ lp = buf;
+ putchar('\n');
+ break;
+ default:
+ *lp++ = c;
+ putchar(c);
+ }
+ }
+}