xref: /netbsd-src/sys/arch/emips/stand/common/boot.c (revision 5a2e6e9910724937b05d363046d346368ea4b294)
1*5a2e6e99Schristos /*	$NetBSD: boot.c,v 1.4 2015/12/13 18:24:50 christos Exp $	*/
25f7e80a8Spooka 
35f7e80a8Spooka /*-
45f7e80a8Spooka  * Copyright (c) 2010 The NetBSD Foundation, Inc.
55f7e80a8Spooka  * Copyright (c) 1999 The NetBSD Foundation, Inc.
65f7e80a8Spooka  * All rights reserved.
75f7e80a8Spooka  *
85f7e80a8Spooka  * This code was written by Alessandro Forin and Neil Pittman
95f7e80a8Spooka  * at Microsoft Research and contributed to The NetBSD Foundation
105f7e80a8Spooka  * by Microsoft Corporation.
115f7e80a8Spooka  *
125f7e80a8Spooka  * Redistribution and use in source and binary forms, with or without
135f7e80a8Spooka  * modification, are permitted provided that the following conditions
145f7e80a8Spooka  * are met:
155f7e80a8Spooka  * 1. Redistributions of source code must retain the above copyright
165f7e80a8Spooka  *    notice, this list of conditions and the following disclaimer.
175f7e80a8Spooka  * 2. Redistributions in binary form must reproduce the above copyright
185f7e80a8Spooka  *    notice, this list of conditions and the following disclaimer in the
195f7e80a8Spooka  *    documentation and/or other materials provided with the distribution.
205f7e80a8Spooka  *
215f7e80a8Spooka  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
225f7e80a8Spooka  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
235f7e80a8Spooka  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
245f7e80a8Spooka  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
255f7e80a8Spooka  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
265f7e80a8Spooka  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
275f7e80a8Spooka  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
285f7e80a8Spooka  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
295f7e80a8Spooka  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
305f7e80a8Spooka  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
315f7e80a8Spooka  * POSSIBILITY OF SUCH DAMAGE.
325f7e80a8Spooka  */
335f7e80a8Spooka 
345f7e80a8Spooka #include <lib/libsa/stand.h>
355f7e80a8Spooka #include <lib/libsa/loadfile.h>
365f7e80a8Spooka #include <lib/libkern/libkern.h>
375f7e80a8Spooka 
385f7e80a8Spooka #include <sys/param.h>
395f7e80a8Spooka #include <sys/exec.h>
405f7e80a8Spooka #include <sys/exec_elf.h>
415f7e80a8Spooka 
425f7e80a8Spooka #include "common.h"
435f7e80a8Spooka #include "bootinfo.h"
445f7e80a8Spooka #include "start.h"
455f7e80a8Spooka 
465f7e80a8Spooka /*
475f7e80a8Spooka  * We won't go overboard with gzip'd kernel names.  After all we can
485f7e80a8Spooka  * still boot a gzip'd kernel called "netbsd.emips" - it doesn't need
495f7e80a8Spooka  * the .gz suffix.
505f7e80a8Spooka  */
515f7e80a8Spooka char *kernelnames[] = {
525f7e80a8Spooka 	"netbsd",	"netbsd.gz",
535f7e80a8Spooka 	"netbsd.old",
545f7e80a8Spooka 	"onetbsd",
555f7e80a8Spooka 	"gennetbsd",
565f7e80a8Spooka 	"nfsnetbsd",
575f7e80a8Spooka 	NULL
585f7e80a8Spooka };
595f7e80a8Spooka 
605f7e80a8Spooka 
615f7e80a8Spooka void main (char *);
625f7e80a8Spooka char *getboot(char *, char*);
635f7e80a8Spooka static int devcanon(char *);
645f7e80a8Spooka 
655f7e80a8Spooka #define OPT_MAX PATH_MAX /* way overkill */
665f7e80a8Spooka 
loadit(char * name,u_long * marks)67*5a2e6e99Schristos static int loadit(char *name, u_long *marks)
685f7e80a8Spooka {
695f7e80a8Spooka 	printf("Loading: %s\n", name);
70*5a2e6e99Schristos 	memset(marks, 0, sizeof(*marks) * MARK_MAX);
715f7e80a8Spooka 	return (loadfile(name, marks, LOAD_ALL));
725f7e80a8Spooka }
735f7e80a8Spooka 
745f7e80a8Spooka /*
755f7e80a8Spooka  * The locore in start.S calls us with an 8KB stack carved after _end.
765f7e80a8Spooka  *
775f7e80a8Spooka  */
785f7e80a8Spooka void
main(char * stack_top)795f7e80a8Spooka main(char *stack_top)
805f7e80a8Spooka {
815f7e80a8Spooka 	int autoboot = 1, win;
825f7e80a8Spooka 	char *name, **namep, *dev, *kernel;
83622b3e34Smartin 	char bootpath[PATH_MAX], options[OPT_MAX];
845f7e80a8Spooka 	uint32_t entry;
855f7e80a8Spooka 	u_long marks[MARK_MAX];
865f7e80a8Spooka 	struct btinfo_symtab bi_syms;
875f7e80a8Spooka 	struct btinfo_bootpath bi_bpath;
885f7e80a8Spooka 
895f7e80a8Spooka 	/* Init all peripherals, esp USART for printf and memory */
905f7e80a8Spooka 	init_board();
915f7e80a8Spooka 
925f7e80a8Spooka 	/* On account of compression, we need a fairly large heap.
935f7e80a8Spooka 	 * To keep things simple, take one meg just below the 16 meg mark.
945f7e80a8Spooka 	 * That allows for a large kernel, and a 16MB configuration still works.
955f7e80a8Spooka 	 */
965f7e80a8Spooka 	setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000);
975f7e80a8Spooka 
985f7e80a8Spooka 	/* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete
995f7e80a8Spooka 	 * and switching the serial line to PuTTY as console. Get a char to pause.
1005f7e80a8Spooka 	 * This delay is also the practice on PCs so.
1015f7e80a8Spooka 	 */
1025f7e80a8Spooka 	Delay(200000);
1035f7e80a8Spooka 	printf("Hit any char to boot..");
104622b3e34Smartin 	(void)GetChar();
1055f7e80a8Spooka 
1065f7e80a8Spooka 	/* print a banner */
1075f7e80a8Spooka 	printf("\n");
1085f7e80a8Spooka 	printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n",
1095f7e80a8Spooka 	    bootprog_rev);
1105f7e80a8Spooka 
1115f7e80a8Spooka 	/* initialise bootinfo structure early */
1125f7e80a8Spooka 	bi_init(BOOTINFO_ADDR);
1135f7e80a8Spooka 
1145f7e80a8Spooka 	/* Default is to auto-boot from the first disk */
1155f7e80a8Spooka 	dev = "0/ace(0,0)/";
1165f7e80a8Spooka 	kernel = kernelnames[0];
1175f7e80a8Spooka 	options[0] = 0;
1185f7e80a8Spooka 
1195f7e80a8Spooka 	win = 0;
1205f7e80a8Spooka 	for (;!win;) {
1215f7e80a8Spooka 	    strcpy(bootpath, dev);
1225f7e80a8Spooka 	    strcat(bootpath, kernel);
1235f7e80a8Spooka 	    name = getboot(bootpath,options);
1245f7e80a8Spooka 
1255f7e80a8Spooka 	    if (name != NULL) {
1265f7e80a8Spooka 	        win = (loadit(name, marks) == 0);
1275f7e80a8Spooka 	    } else if (autoboot)
1285f7e80a8Spooka 	        break;
1295f7e80a8Spooka 	    autoboot = 0;
1305f7e80a8Spooka 	}
1315f7e80a8Spooka 
1325f7e80a8Spooka 	if (!win) {
1335f7e80a8Spooka 		for (namep = kernelnames, win = 0; *namep != NULL && !win;
1345f7e80a8Spooka 		    namep++) {
1355f7e80a8Spooka 			kernel = *namep;
1365f7e80a8Spooka 			strcpy(bootpath, dev);
1375f7e80a8Spooka 			strcat(bootpath, kernel);
1385f7e80a8Spooka 			win = (loadit(bootpath, marks) == 0);
1395f7e80a8Spooka 			if (win) {
1405f7e80a8Spooka 				name = bootpath;
1415f7e80a8Spooka 			}
1425f7e80a8Spooka 		}
1435f7e80a8Spooka 	}
1445f7e80a8Spooka 	if (!win)
1455f7e80a8Spooka 		goto fail;
1465f7e80a8Spooka 
1475f7e80a8Spooka 	strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN);
1485f7e80a8Spooka 	bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
1495f7e80a8Spooka 
1505f7e80a8Spooka 	entry = marks[MARK_ENTRY];
1515f7e80a8Spooka 	bi_syms.nsym = marks[MARK_NSYM];
1525f7e80a8Spooka 	bi_syms.ssym = marks[MARK_SYM];
1535f7e80a8Spooka 	bi_syms.esym = marks[MARK_END];
1545f7e80a8Spooka 	bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
1555f7e80a8Spooka 
1565f7e80a8Spooka 	printf("Starting at 0x%x\n\n", entry);
1575f7e80a8Spooka 	call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo);
1585f7e80a8Spooka 	(void)printf("KERNEL RETURNED!\n");
1595f7e80a8Spooka 
1605f7e80a8Spooka fail:
1615f7e80a8Spooka 	(void)printf("Boot failed!  Halting...\n");
1625f7e80a8Spooka }
1635f7e80a8Spooka 
1645f7e80a8Spooka static inline int
parse(char * cmd,char * kname,char * optarg)1655f7e80a8Spooka parse(char *cmd, char *kname, char *optarg)
1665f7e80a8Spooka {
1675f7e80a8Spooka 	char *arg = cmd;
1685f7e80a8Spooka 	char *ep, *p;
1695f7e80a8Spooka 	int c, i;
1705f7e80a8Spooka 
1715f7e80a8Spooka 	while ((c = *arg++)) {
1725f7e80a8Spooka 	    /* skip leading blanks */
1735f7e80a8Spooka 	    if (c == ' ' || c == '\t' || c == '\n')
1745f7e80a8Spooka 	        continue;
1755f7e80a8Spooka 	    /* find separator, or eol */
1765f7e80a8Spooka 	    for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
1775f7e80a8Spooka 	    ep = p;
1785f7e80a8Spooka 	    /* trim if separator */
1795f7e80a8Spooka 	    if (*p)
1805f7e80a8Spooka 	        *p++ = 0;
1815f7e80a8Spooka 	    /* token is either "-opts" or "kernelname" */
1825f7e80a8Spooka 	    if (c == '-') {
1835f7e80a8Spooka 	        /* no overflow because whole line same length as optarg anyways */
1845f7e80a8Spooka 	        while ((c = *arg++)) {
1855f7e80a8Spooka 	            *optarg++ = c;
1865f7e80a8Spooka 	        }
1875f7e80a8Spooka 	        *optarg = 0;
1885f7e80a8Spooka 	    } else {
1895f7e80a8Spooka 	        arg--;
1905f7e80a8Spooka 	        if ((i = ep - arg)) {
1915f7e80a8Spooka 	            if ((size_t)i >= PATH_MAX)
1925f7e80a8Spooka 	                return -1;
1935f7e80a8Spooka 	            memcpy(kname, arg, i + 1);
1945f7e80a8Spooka 	        }
1955f7e80a8Spooka 	    }
1965f7e80a8Spooka 	    arg = p;
1975f7e80a8Spooka 	}
1985f7e80a8Spooka 	return 0;
1995f7e80a8Spooka }
2005f7e80a8Spooka 
2015f7e80a8Spooka /* String returned is zero-terminated and at most PATH_MAX chars */
2025f7e80a8Spooka static inline void
getstr(char * cmd,int c)2035f7e80a8Spooka getstr(char *cmd, int c)
2045f7e80a8Spooka {
2055f7e80a8Spooka 	char *s;
2065f7e80a8Spooka 
2075f7e80a8Spooka 	s = cmd;
2085f7e80a8Spooka 	if (c == 0)
2095f7e80a8Spooka 	    c = GetChar();
2105f7e80a8Spooka 	for (;;) {
2115f7e80a8Spooka 	    switch (c) {
2125f7e80a8Spooka 	    case 0:
2135f7e80a8Spooka 	        break;
2145f7e80a8Spooka 	    case '\177':
2155f7e80a8Spooka 	    case '\b':
2165f7e80a8Spooka 	        if (s > cmd) {
2175f7e80a8Spooka 	            s--;
2185f7e80a8Spooka 	            printf("\b \b");
2195f7e80a8Spooka 	        }
2205f7e80a8Spooka 	        break;
2215f7e80a8Spooka 	    case '\n':
2225f7e80a8Spooka 	    case '\r':
2235f7e80a8Spooka 	        *s = 0;
2245f7e80a8Spooka 	        return;
2255f7e80a8Spooka 	    default:
2265f7e80a8Spooka 	        if ((s - cmd) < (PATH_MAX - 1))
2275f7e80a8Spooka 	            *s++ = c;
2285f7e80a8Spooka 	        xputchar(c);
2295f7e80a8Spooka 	    }
2305f7e80a8Spooka 	    c = GetChar();
2315f7e80a8Spooka 	}
2325f7e80a8Spooka }
2335f7e80a8Spooka 
getboot(char * kname,char * optarg)2345f7e80a8Spooka char *getboot(char *kname, char* optarg)
2355f7e80a8Spooka {
2365f7e80a8Spooka 	char c = 0;
2375f7e80a8Spooka 	char cmd[PATH_MAX];
2385f7e80a8Spooka 
2395f7e80a8Spooka 	printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname);
2405f7e80a8Spooka 	if ((c = GetChar()) == -1)
2415f7e80a8Spooka 	    return NULL;
2425f7e80a8Spooka 
2435f7e80a8Spooka 	cmd[0] = 0;
2445f7e80a8Spooka 	getstr(cmd,c);
2455f7e80a8Spooka 	xputchar('\n');
2465f7e80a8Spooka 	if (parse(cmd,kname,optarg))
2475f7e80a8Spooka 	    xputchar('\a');
2485f7e80a8Spooka 	else if (devcanon(kname) == 0)
2495f7e80a8Spooka 	    return kname;
2505f7e80a8Spooka 	return NULL;
2515f7e80a8Spooka }
2525f7e80a8Spooka 
2535f7e80a8Spooka /*
2545f7e80a8Spooka  * Make bootpath canonical, provides defaults when missing
2555f7e80a8Spooka  */
2565f7e80a8Spooka static int
devcanon(char * fname)2575f7e80a8Spooka devcanon(char *fname)
2585f7e80a8Spooka {
2595f7e80a8Spooka 	int ctlr = 0, unit = 0, part = 0;
260622b3e34Smartin 	int c;
2615f7e80a8Spooka 	char device_name[20];
2625f7e80a8Spooka 	char file_name[PATH_MAX];
2635f7e80a8Spooka 	const char *cp;
2645f7e80a8Spooka 	char *ncp;
2655f7e80a8Spooka 
2665f7e80a8Spooka 	//printf("devcanon(%s)\n",fname);
2675f7e80a8Spooka 
2685f7e80a8Spooka 	cp = fname;
2695f7e80a8Spooka 	ncp = device_name;
2705f7e80a8Spooka 
2715f7e80a8Spooka 	/* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file
2725f7e80a8Spooka 	 * Defaults: ctrl=0, name='ace', unit=0, part=0, file=<none>
2735f7e80a8Spooka 	 */
2745f7e80a8Spooka 
2755f7e80a8Spooka 	/* get controller number */
2765f7e80a8Spooka 	if ((c = *cp) >= '0' && c <= '9') {
2775f7e80a8Spooka 	    ctlr = c - '0';
2785f7e80a8Spooka 	    c = *++cp;
2795f7e80a8Spooka 	    if (c != '/')
2805f7e80a8Spooka 	        return (ENXIO);
2815f7e80a8Spooka 	    c = *++cp;
2825f7e80a8Spooka 	}
2835f7e80a8Spooka 
2845f7e80a8Spooka 	/* get device name */
2855f7e80a8Spooka 	while ((c = *cp) != '\0') {
2865f7e80a8Spooka 	    if ((c == '(') || (c == '/')) {
2875f7e80a8Spooka 	        cp++;
2885f7e80a8Spooka 	        break;
2895f7e80a8Spooka 	    }
2905f7e80a8Spooka 	    if (ncp < device_name + sizeof(device_name) - 1)
2915f7e80a8Spooka 	        *ncp++ = c;
2925f7e80a8Spooka 	    cp++;
2935f7e80a8Spooka 	}
2945f7e80a8Spooka 	/* set default if missing */
2955f7e80a8Spooka 	if (ncp == device_name) {
2965f7e80a8Spooka 	    strcpy(device_name,"ace");
2975f7e80a8Spooka 	    ncp += 3;
2985f7e80a8Spooka 	}
2995f7e80a8Spooka 
3005f7e80a8Spooka 	/* get device number */
3015f7e80a8Spooka 	if ((c = *cp) >= '0' && c <= '9') {
3025f7e80a8Spooka 	    unit = c - '0';
3035f7e80a8Spooka 	    c = *++cp;
3045f7e80a8Spooka 	}
3055f7e80a8Spooka 
3065f7e80a8Spooka 	if (c == ',') {
3075f7e80a8Spooka 	    /* get partition number */
3085f7e80a8Spooka 	    if ((c = *++cp) >= '0' && c <= '9') {
3095f7e80a8Spooka 	        part = c - '0';
3105f7e80a8Spooka 	        c = *++cp;
3115f7e80a8Spooka 	    }
3125f7e80a8Spooka 	}
3135f7e80a8Spooka 
3145f7e80a8Spooka 	if (c == ')')
3155f7e80a8Spooka 	    c = *++cp;
3165f7e80a8Spooka 	if (c == '/')
3175f7e80a8Spooka 	    cp++;
3185f7e80a8Spooka 
3195f7e80a8Spooka 	*ncp = '\0';
3205f7e80a8Spooka 
3215f7e80a8Spooka 	/* Copy kernel name before we overwrite, then do it */
3225f7e80a8Spooka 	strcpy(file_name, (*cp) ? cp : kernelnames[0]);
323b50b466aSchristos 	snprintf(fname, PATH_MAX, "%c/%s(%c,%c)/%s",
3245f7e80a8Spooka 	        ctlr + '0', device_name, unit + '0', part + '0', file_name);
3255f7e80a8Spooka 
3265f7e80a8Spooka 	//printf("devcanon -> %s\n",fname);
3275f7e80a8Spooka 
3285f7e80a8Spooka 	return (0);
3295f7e80a8Spooka }
330