Home | History | Annotate | Line # | Download | only in boot
boot.c revision 1.10.16.1
      1 /*	$NetBSD: boot.c,v 1.10.16.1 2008/04/03 12:42:13 mjf Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jonathan Stone, Michael Hitch, Simon Burge and Wayne Knowles.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Copyright (c) 1992, 1993
     41  *	The Regents of the University of California.  All rights reserved.
     42  *
     43  * This code is derived from software contributed to Berkeley by
     44  * Ralph Campbell.
     45  *
     46  * Redistribution and use in source and binary forms, with or without
     47  * modification, are permitted provided that the following conditions
     48  * are met:
     49  * 1. Redistributions of source code must retain the above copyright
     50  *    notice, this list of conditions and the following disclaimer.
     51  * 2. Redistributions in binary form must reproduce the above copyright
     52  *    notice, this list of conditions and the following disclaimer in the
     53  *    documentation and/or other materials provided with the distribution.
     54  * 3. Neither the name of the University nor the names of its contributors
     55  *    may be used to endorse or promote products derived from this software
     56  *    without specific prior written permission.
     57  *
     58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     68  * SUCH DAMAGE.
     69  *
     70  *	@(#)boot.c	8.1 (Berkeley) 6/10/93
     71  */
     72 
     73 #include <lib/libsa/stand.h>
     74 #include <lib/libsa/loadfile.h>
     75 #include <lib/libsa/dev_net.h>
     76 #include <lib/libkern/libkern.h>
     77 
     78 #include <sys/param.h>
     79 #include <sys/boot_flag.h>
     80 #include <sys/exec.h>
     81 #include <sys/exec_elf.h>
     82 
     83 #include <machine/cpu.h>
     84 
     85 #include <cobalt/dev/gtreg.h>
     86 
     87 #include "boot.h"
     88 #include "cons.h"
     89 #include "common.h"
     90 #include "bootinfo.h"
     91 
     92 char *kernelnames[] = {
     93 	"netbsd",
     94 	"netbsd.gz",
     95 	"onetbsd",
     96 	"onetbsd.gz",
     97 	"netbsd.bak",
     98 	"netbsd.bak.gz",
     99 	"netbsd.old",
    100 	"netbsd.old.gz",
    101 	"netbsd.cobalt",
    102 	"netbsd.cobalt.gz",
    103 	"netbsd.elf",
    104 	"netbsd.elf.gz",
    105 	NULL
    106 };
    107 
    108 u_int cobalt_id;
    109 static const char * const cobalt_model[] =
    110 {
    111 	[0]                  = "Unknown Cobalt",
    112 	[COBALT_ID_QUBE2700] = "Cobalt Qube 2700",
    113 	[COBALT_ID_RAQ]      = "Cobalt RaQ",
    114 	[COBALT_ID_QUBE2]    = "Cobalt Qube 2",
    115 	[COBALT_ID_RAQ2]     = "Cobalt RaQ 2"
    116 };
    117 #define COBALT_MODELS	__arraycount(cobalt_model)
    118 
    119 extern u_long end;		/* Boot loader code end address */
    120 void start(void);
    121 
    122 static char *bootstring;
    123 
    124 static int patch_bootstring(char *bootspec);
    125 static int get_bsdbootname(char **, char **, int *);
    126 static int parse_bootname(char *, int, char **, char **);
    127 static void prominit(unsigned int memsize);
    128 static void print_banner(unsigned int memsize);
    129 static u_int read_board_id(void);
    130 
    131 void cpu_reboot(void);
    132 
    133 int main(unsigned int memsize);
    134 
    135 /*
    136  * Perform CPU reboot.
    137  */
    138 void
    139 cpu_reboot(void)
    140 {
    141 
    142 	printf("rebooting...\n\n");
    143 
    144 	*(volatile uint8_t *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET;
    145 	printf("WARNING: reboot failed!\n");
    146 
    147 	for (;;)
    148 		;
    149 }
    150 
    151 /*
    152  * Substitute root value with NetBSD root partition name.
    153  */
    154 int
    155 patch_bootstring(char *bootspec)
    156 {
    157 	char *sp = bootstring;
    158 	uint8_t unit, part;
    159 	int dev;
    160 	char *file;
    161 
    162 	DPRINTF(("patch_bootstring: %s\n", bootspec));
    163 
    164 	/* get boot parameters */
    165 	if (devparse(bootspec, &dev, &unit, &part, (const char **)&file) != 0)
    166 		unit = part = 0;
    167 
    168 	DPRINTF(("patch_bootstring: unit = %d, part = %d\n", unit, part));
    169 
    170 	/* take out the 'root=xxx' parameter */
    171 	if ((sp = strstr(bootstring, "root=")) != NULL) {
    172 		const char *end;
    173 
    174 		end = strchr(sp, ' ');
    175 
    176 		/* strip off leading spaces */
    177 		for (--sp; (sp > bootstring) && (*sp == ' '); --sp)
    178 			;
    179 
    180 		if (end != NULL)
    181 			strcpy(++sp, end);
    182 		else
    183 			*++sp = '\0';
    184 	}
    185 
    186 	DPRINTF(("patch_bootstring: [%s]\n", bootstring));
    187 
    188 #define DEVNAMESIZE	(MAXDEVNAME + sizeof(" root=/dev/hd") + sizeof("0a"))
    189 	if (strcmp(devsw[dev].dv_name, "wd") == 0 &&
    190 	    strlen(bootstring) <= (511 - DEVNAMESIZE)) {
    191 		int len;
    192 
    193 		/* omit "nfsroot=" arg on wd boot */
    194 		if ((sp = strstr(bootstring, "nfsroot=")) != NULL) {
    195 			const char *end;
    196 
    197 			end = strchr(sp, ' ');
    198 
    199 			/* strip off leading spaces */
    200 			for (--sp; (sp > bootstring) && (*sp == ' '); --sp)
    201 				;
    202 
    203 			if (end != NULL)
    204 				strcpy(++sp, end);
    205 			else
    206 				*++sp = '\0';
    207 		}
    208 
    209 		/* bsd notation -> linux notation (wd0a -> hda1) */
    210 		strcat(bootstring, " root=/dev/hd");
    211 
    212 		len = strlen(bootstring);
    213 		bootstring[len++] = unit + 'a';
    214 		bootstring[len++] = part + '1';
    215 		bootstring[len++] = '\0';
    216 	}
    217 
    218 	DPRINTF(("patch_bootstring: -> %s\n", bootstring));
    219 	return 0;
    220 }
    221 
    222 /*
    223  * Extract NetBSD boot specification
    224  */
    225 static int
    226 get_bsdbootname(char **dev, char **kname, int *howtop)
    227 {
    228 	int len;
    229 	int bootunit, bootpart;
    230 	char *bootstr_dev, *bootstr_kname;
    231 	char *prompt_dev, *prompt_kname;
    232 	char *ptr, *spec;
    233 	char c, namebuf[PATH_MAX];
    234 	static char bootdev[] = "wd0a";
    235 	static char nfsbootdev[] = "nfs";
    236 
    237 	bootstr_dev = prompt_dev = NULL;
    238 	bootstr_kname = prompt_kname = NULL;
    239 
    240 	/* first, get root device specified by the firmware */
    241 	spec = bootstring;
    242 
    243 	/* assume the last one is valid */
    244 	while ((spec = strstr(spec, "root=")) != NULL) {
    245 		spec += 5;	/* skip 'root=' */
    246 		ptr = strchr(spec, ' ');
    247 		len = (ptr == NULL) ? strlen(spec) : ptr - spec;
    248 		/* decode unit and part from "/dev/hd[ab][1-4]" strings */
    249 		if (len == 9 && memcmp("/dev/hd", spec, 7) == 0) {
    250 			bootunit = spec[7] - 'a';
    251 			bootpart = spec[8] - '1';
    252 			if (bootunit >= 0 && bootunit < 2 &&
    253 			    bootpart >= 0 && bootpart < 4) {
    254 				bootdev[sizeof(bootdev) - 3] = '0' + bootunit;
    255 #if 0				/* bootpart is fdisk partition of Linux root */
    256 				bootdev[sizeof(bootdev) - 2] = 'a' + bootpart;
    257 #endif
    258 				bootstr_dev = bootdev;
    259 			}
    260 		}
    261 		spec += len;
    262 	}
    263 
    264 	/* second, get bootname from bootstrings */
    265 	if ((spec = strstr(bootstring, "nbsd=")) != NULL) {
    266 		ptr = strchr(spec, ' ');
    267 		spec += 5; 	/* skip 'nbsd=' */
    268 		len = (ptr == NULL) ? strlen(spec) : ptr - spec;
    269 		if (len > 0) {
    270 			if (parse_bootname(spec, len,
    271 			    &bootstr_dev, &bootstr_kname))
    272 				return 1;
    273 		}
    274 	}
    275 
    276 	/* third, check if netboot */
    277 	if (strstr(bootstring, "nfsroot=") != NULL) {
    278 		bootstr_dev = nfsbootdev;
    279 	}
    280 
    281 	DPRINTF(("bootstr_dev = %s, bootstr_kname = %s\n",
    282 	    bootstr_dev ? bootstr_dev : "<NULL>",
    283 	    bootstr_kname ? bootstr_kname : "<NULL>"));
    284 
    285 	spec = NULL;
    286 	len = 0;
    287 
    288 	memset(namebuf, 0, sizeof namebuf);
    289 	printf("Boot [%s:%s]: ",
    290 	    bootstr_dev ? bootstr_dev : DEFBOOTDEV,
    291 	    bootstr_kname ? bootstr_kname : DEFKERNELNAME);
    292 
    293 	if (tgets(namebuf) == -1)
    294 		printf("\n");
    295 
    296 	ptr = namebuf;
    297 	while ((c = *ptr) != '\0') {
    298 		while (c == ' ')
    299 			c = *++ptr;
    300 		if (c == '\0')
    301 			break;
    302 		if (c == '-') {
    303 			while ((c = *++ptr) && c != ' ')
    304 				BOOT_FLAG(c, *howtop);
    305 		} else {
    306 			spec = ptr;
    307 			while ((c = *++ptr) && c != ' ')
    308 				;
    309 			if (c)
    310 				*ptr++ = '\0';
    311 			len = strlen(spec);
    312 		}
    313 	}
    314 
    315 	if (len > 0) {
    316 		if (parse_bootname(spec, len, &prompt_dev, &prompt_kname))
    317 			return 1;
    318 	}
    319 
    320 	DPRINTF(("prompt_dev = %s, prompt_kname = %s\n",
    321 	    prompt_dev ? prompt_dev : "<NULL>",
    322 	    prompt_kname ? prompt_kname : "<NULL>"));
    323 
    324 	if (prompt_dev)
    325 		*dev = prompt_dev;
    326 	else
    327 		*dev = bootstr_dev;
    328 
    329 	if (prompt_kname)
    330 		*kname = prompt_kname;
    331 	else
    332 		*kname = bootstr_kname;
    333 
    334 	DPRINTF(("dev = %s, kname = %s\n",
    335 	    *dev ? *dev : "<NULL>",
    336 	    *kname ? *kname : "<NULL>"));
    337 
    338 	return 0;
    339 }
    340 
    341 static int
    342 parse_bootname(char *spec, int len, char **dev, char **kname)
    343 {
    344 	char *bootname, *ptr;
    345 
    346 	bootname = alloc(len + 1);
    347 	if (bootname == NULL)
    348 		return 1;
    349 	memcpy(bootname, spec, len);
    350 	bootname[len] = '\0';
    351 
    352 	if ((ptr = memchr(bootname, ':', len)) != NULL) {
    353 		/* "wdXX:kernel" */
    354 		*ptr = '\0';
    355 		*dev = bootname;
    356 		if (*++ptr)
    357 			*kname = ptr;
    358 	} else
    359 		/* "kernel" */
    360 		*kname = bootname;
    361 	return 0;
    362 }
    363 
    364 /*
    365  * Get the bootstring from PROM.
    366  */
    367 void
    368 prominit(unsigned int memsize)
    369 {
    370 
    371 	bootstring = (char *)(memsize - 512);
    372 	bootstring[511] = '\0';
    373 }
    374 
    375 /*
    376  * Print boot message.
    377  */
    378 void
    379 print_banner(unsigned int memsize)
    380 {
    381 
    382 	printf("\n");
    383 	printf(">> %s " NETBSD_VERS " Bootloader, Revision %s [@%p]\n",
    384 			bootprog_name, bootprog_rev, (void*)&start);
    385 	printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
    386 	printf(">> Model:\t\t%s\n", cobalt_model[cobalt_id]);
    387 	printf(">> Memory:\t\t%u k\n", (memsize - MIPS_KSEG0_START) / 1024);
    388 	printf(">> PROM boot string:\t%s\n", bootstring);
    389 }
    390 
    391 u_int
    392 read_board_id(void)
    393 {
    394 	uint32_t tag, reg;
    395 
    396 #define PCIB_PCI_BUS		0
    397 #define PCIB_PCI_DEV		9
    398 #define PCIB_PCI_FUNC		0
    399 #define PCIB_BOARD_ID_REG	0x94
    400 #define COBALT_BOARD_ID(reg)	((reg & 0x000000f0) >> 4)
    401 
    402 	tag = (PCIB_PCI_BUS << 16) | (PCIB_PCI_DEV << 11) |
    403 	    (PCIB_PCI_FUNC << 8);
    404 	reg = pcicfgread(tag, PCIB_BOARD_ID_REG);
    405 
    406 	return COBALT_BOARD_ID(reg);
    407 }
    408 
    409 /*
    410  * Entry point.
    411  * Parse PROM boot string, load the kernel and jump into it
    412  */
    413 int
    414 main(unsigned int memsize)
    415 {
    416 	char **namep, *dev, *kernel, *bi_addr;
    417 	char bootpath[PATH_MAX];
    418 	int win;
    419 	u_long marks[MARK_MAX];
    420 	void (*entry)(unsigned int, u_int, char *);
    421 
    422 	struct btinfo_flags bi_flags;
    423 	struct btinfo_symtab bi_syms;
    424 	struct btinfo_bootpath bi_bpath;
    425 	struct btinfo_howto bi_howto;
    426 	int addr, speed, howto;
    427 
    428 	try_bootp = 1;
    429 
    430 	/* Initialize boot info early */
    431 	dev = NULL;
    432 	kernel = NULL;
    433 	howto = 0x0;
    434 	bi_flags.bi_flags = 0x0;
    435 	bi_addr = bi_init();
    436 
    437 	cobalt_id = read_board_id();
    438 	prominit(memsize);
    439 	if (cninit(&addr, &speed) != NULL)
    440 		bi_flags.bi_flags |= BI_SERIAL_CONSOLE;
    441 
    442 	print_banner(memsize);
    443 
    444 	memset(marks, 0, sizeof marks);
    445 	get_bsdbootname(&dev, &kernel, &howto);
    446 
    447 	if (kernel != NULL) {
    448 		DPRINTF(("kernel: %s\n", kernel));
    449 		kernelnames[0] = kernel;
    450 		kernelnames[1] = NULL;
    451 	} else {
    452 		DPRINTF(("kernel: NULL\n"));
    453 	}
    454 
    455 	win = 0;
    456 	DPRINTF(("Kernel names: %p\n", kernelnames));
    457 	for (namep = kernelnames, win = 0; (*namep != NULL) && !win; namep++) {
    458 		kernel = *namep;
    459 
    460 		bootpath[0] = '\0';
    461 
    462 		strcpy(bootpath, dev ? dev : DEFBOOTDEV);
    463 		strcat(bootpath, ":");
    464 		strcat(bootpath, kernel);
    465 
    466 		printf("Loading: %s", bootpath);
    467 		if (howto)
    468 			printf(" (howto 0x%x)", howto);
    469 		printf("\n");
    470 		patch_bootstring(bootpath);
    471 		win = (loadfile(bootpath, marks, LOAD_ALL) != -1);
    472 	}
    473 
    474 	if (win) {
    475 		strncpy(bi_bpath.bootpath, kernel, BTINFO_BOOTPATH_LEN);
    476 		bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
    477 
    478 		entry = (void *)marks[MARK_ENTRY];
    479 		bi_syms.nsym = marks[MARK_NSYM];
    480 		bi_syms.ssym = marks[MARK_SYM];
    481 		bi_syms.esym = marks[MARK_END];
    482 		bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
    483 
    484 		bi_add(&bi_flags, BTINFO_FLAGS, sizeof(bi_flags));
    485 
    486 		bi_howto.bi_howto = howto;
    487 		bi_add(&bi_howto, BTINFO_HOWTO, sizeof(bi_howto));
    488 
    489 		entry = (void *)marks[MARK_ENTRY];
    490 
    491 		DPRINTF(("Bootinfo @ 0x%x\n", bi_addr));
    492 		printf("Starting at 0x%x\n\n", (u_int)entry);
    493 		(*entry)(memsize, BOOTINFO_MAGIC, bi_addr);
    494 	}
    495 
    496 	(void)printf("Boot failed! Rebooting...\n");
    497 	return 0;
    498 }
    499