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