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