NetBSD/sys/arch/emips/stand/common/boot.c
2015-12-13 18:24:50 +00:00

330 lines
7.9 KiB
C

/* $NetBSD: boot.c,v 1.4 2015/12/13 18:24:50 christos Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was written by Alessandro Forin and Neil Pittman
* at Microsoft Research and contributed to The NetBSD Foundation
* by Microsoft Corporation.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>
#include <lib/libkern/libkern.h>
#include <sys/param.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include "common.h"
#include "bootinfo.h"
#include "start.h"
/*
* We won't go overboard with gzip'd kernel names. After all we can
* still boot a gzip'd kernel called "netbsd.emips" - it doesn't need
* the .gz suffix.
*/
char *kernelnames[] = {
"netbsd", "netbsd.gz",
"netbsd.old",
"onetbsd",
"gennetbsd",
"nfsnetbsd",
NULL
};
void main (char *);
char *getboot(char *, char*);
static int devcanon(char *);
#define OPT_MAX PATH_MAX /* way overkill */
static int loadit(char *name, u_long *marks)
{
printf("Loading: %s\n", name);
memset(marks, 0, sizeof(*marks) * MARK_MAX);
return (loadfile(name, marks, LOAD_ALL));
}
/*
* The locore in start.S calls us with an 8KB stack carved after _end.
*
*/
void
main(char *stack_top)
{
int autoboot = 1, win;
char *name, **namep, *dev, *kernel;
char bootpath[PATH_MAX], options[OPT_MAX];
uint32_t entry;
u_long marks[MARK_MAX];
struct btinfo_symtab bi_syms;
struct btinfo_bootpath bi_bpath;
/* Init all peripherals, esp USART for printf and memory */
init_board();
/* On account of compression, we need a fairly large heap.
* To keep things simple, take one meg just below the 16 meg mark.
* That allows for a large kernel, and a 16MB configuration still works.
*/
setheap((void *)(0x81000000-(1024*1024)), (void *)0x81000000);
/* On the BEE3 and the Giano simulator, we need a sec between the serial-line download complete
* and switching the serial line to PuTTY as console. Get a char to pause.
* This delay is also the practice on PCs so.
*/
Delay(200000);
printf("Hit any char to boot..");
(void)GetChar();
/* print a banner */
printf("\n");
printf("NetBSD/emips " NETBSD_VERS " " BOOT_TYPE_NAME " Bootstrap, Revision %s\n",
bootprog_rev);
/* initialise bootinfo structure early */
bi_init(BOOTINFO_ADDR);
/* Default is to auto-boot from the first disk */
dev = "0/ace(0,0)/";
kernel = kernelnames[0];
options[0] = 0;
win = 0;
for (;!win;) {
strcpy(bootpath, dev);
strcat(bootpath, kernel);
name = getboot(bootpath,options);
if (name != NULL) {
win = (loadit(name, marks) == 0);
} else if (autoboot)
break;
autoboot = 0;
}
if (!win) {
for (namep = kernelnames, win = 0; *namep != NULL && !win;
namep++) {
kernel = *namep;
strcpy(bootpath, dev);
strcat(bootpath, kernel);
win = (loadit(bootpath, marks) == 0);
if (win) {
name = bootpath;
}
}
}
if (!win)
goto fail;
strncpy(bi_bpath.bootpath, name/*kernel?*/, BTINFO_BOOTPATH_LEN);
bi_add(&bi_bpath, BTINFO_BOOTPATH, sizeof(bi_bpath));
entry = marks[MARK_ENTRY];
bi_syms.nsym = marks[MARK_NSYM];
bi_syms.ssym = marks[MARK_SYM];
bi_syms.esym = marks[MARK_END];
bi_add(&bi_syms, BTINFO_SYMTAB, sizeof(bi_syms));
printf("Starting at 0x%x\n\n", entry);
call_kernel(entry, name, options, BOOTINFO_MAGIC, bootinfo);
(void)printf("KERNEL RETURNED!\n");
fail:
(void)printf("Boot failed! Halting...\n");
}
static inline int
parse(char *cmd, char *kname, char *optarg)
{
char *arg = cmd;
char *ep, *p;
int c, i;
while ((c = *arg++)) {
/* skip leading blanks */
if (c == ' ' || c == '\t' || c == '\n')
continue;
/* find separator, or eol */
for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
ep = p;
/* trim if separator */
if (*p)
*p++ = 0;
/* token is either "-opts" or "kernelname" */
if (c == '-') {
/* no overflow because whole line same length as optarg anyways */
while ((c = *arg++)) {
*optarg++ = c;
}
*optarg = 0;
} else {
arg--;
if ((i = ep - arg)) {
if ((size_t)i >= PATH_MAX)
return -1;
memcpy(kname, arg, i + 1);
}
}
arg = p;
}
return 0;
}
/* String returned is zero-terminated and at most PATH_MAX chars */
static inline void
getstr(char *cmd, int c)
{
char *s;
s = cmd;
if (c == 0)
c = GetChar();
for (;;) {
switch (c) {
case 0:
break;
case '\177':
case '\b':
if (s > cmd) {
s--;
printf("\b \b");
}
break;
case '\n':
case '\r':
*s = 0;
return;
default:
if ((s - cmd) < (PATH_MAX - 1))
*s++ = c;
xputchar(c);
}
c = GetChar();
}
}
char *getboot(char *kname, char* optarg)
{
char c = 0;
char cmd[PATH_MAX];
printf("\nDefault: %s%s %s\nboot: ", (*optarg) ? "-" : "", optarg, kname);
if ((c = GetChar()) == -1)
return NULL;
cmd[0] = 0;
getstr(cmd,c);
xputchar('\n');
if (parse(cmd,kname,optarg))
xputchar('\a');
else if (devcanon(kname) == 0)
return kname;
return NULL;
}
/*
* Make bootpath canonical, provides defaults when missing
*/
static int
devcanon(char *fname)
{
int ctlr = 0, unit = 0, part = 0;
int c;
char device_name[20];
char file_name[PATH_MAX];
const char *cp;
char *ncp;
//printf("devcanon(%s)\n",fname);
cp = fname;
ncp = device_name;
/* expect a string like '0/ace(0,0)/netbsd' e.g. ctrl/name(unit,part)/file
* Defaults: ctrl=0, name='ace', unit=0, part=0, file=<none>
*/
/* get controller number */
if ((c = *cp) >= '0' && c <= '9') {
ctlr = c - '0';
c = *++cp;
if (c != '/')
return (ENXIO);
c = *++cp;
}
/* get device name */
while ((c = *cp) != '\0') {
if ((c == '(') || (c == '/')) {
cp++;
break;
}
if (ncp < device_name + sizeof(device_name) - 1)
*ncp++ = c;
cp++;
}
/* set default if missing */
if (ncp == device_name) {
strcpy(device_name,"ace");
ncp += 3;
}
/* get device number */
if ((c = *cp) >= '0' && c <= '9') {
unit = c - '0';
c = *++cp;
}
if (c == ',') {
/* get partition number */
if ((c = *++cp) >= '0' && c <= '9') {
part = c - '0';
c = *++cp;
}
}
if (c == ')')
c = *++cp;
if (c == '/')
cp++;
*ncp = '\0';
/* Copy kernel name before we overwrite, then do it */
strcpy(file_name, (*cp) ? cp : kernelnames[0]);
snprintf(fname, PATH_MAX, "%c/%s(%c,%c)/%s",
ctlr + '0', device_name, unit + '0', part + '0', file_name);
//printf("devcanon -> %s\n",fname);
return (0);
}