/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Tohru Nishimura.
*
* 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.
*/
nata = pcilookup(PCI_CLASS_IDE, lata, 2);
if (nata == 0)
nata = pcilookup(PCI_CLASS_RAID, lata, 2);
if (nata == 0)
nata = pcilookup(PCI_CLASS_MISCSTORAGE, lata, 2);
if (nata == 0)
nata = pcilookup(PCI_CLASS_SCSI, lata, 2);
nnif = pcilookup(PCI_CLASS_ETH, lnif, 2);
nusb = pcilookup(PCI_CLASS_USB, lusb, 3);
#ifdef DEBUG
if (nata == 0)
printf("No IDE/SATA found\n");
else for (n = 0; n < nata; n++) {
int b, d, f, bdf, pvd;
bdf = lata[n].bdf;
pvd = lata[n].pvd;
pcidecomposetag(bdf, &b, &d, &f);
printf("%04x.%04x DSK %02d:%02d:%02d\n",
PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
}
if (nnif == 0)
printf("no NET found\n");
else for (n = 0; n < nnif; n++) {
int b, d, f, bdf, pvd;
bdf = lnif[n].bdf;
pvd = lnif[n].pvd;
pcidecomposetag(bdf, &b, &d, &f);
printf("%04x.%04x NET %02d:%02d:%02d\n",
PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
}
if (nusb == 0)
printf("no USB found\n");
else for (n = 0; n < nusb; n++) {
int b, d, f, bdf, pvd;
bdf = lusb[0].bdf;
pvd = lusb[0].pvd;
pcidecomposetag(bdf, &b, &d, &f);
printf("%04x.%04x USB %02d:%02d:%02d\n",
PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
}
#endif
pcisetup();
pcifixup();
/*
* When argc is too big then it is probably a pointer, which could
* indicate that we were launched as a Linux kernel module using
* "bootm".
*/
if (argc > MAX_ARGS) {
if (argv != NULL) {
/*
* initrd image was loaded:
* check if it contains a valid altboot command line
*/
char *p = (char *)argv;
/* look for a PATA drive configuration string under the arguments */
for (n = 1; n < argc; n++) {
if (strncmp(argv[n], "ide:", 4) == 0 &&
argv[n][4] >= '0' && argv[n][4] <= '2') {
drive_config = &argv[n][4];
break;
}
}
/* initialize a disk driver */
for (i = 0, n = 0; i < nata; i++)
n += dskdv_init(&lata[i]);
if (n == 0)
printf("IDE/SATA device driver was not found\n");
/* initialize a network interface */
for (n = 0; n < nnif; n++)
if (netif_init(&lnif[n]) != 0)
break;
if (n >= nnif)
printf("no NET device driver was found\n");
/* wait 2s for user to enter interactive mode */
for (n = 200; n >= 0; n--) {
if (n % 100 == 0)
printf("\rHit any key to enter interactive mode: %d",
n / 100);
if (tstchar()) {
#ifdef DEBUG
unsigned c;
c = toupper(getchar());
if (c == 'C') {
/* controller test terminal */
sat_test();
n = 200;
continue;
}
else if (c == 'F') {
/* find strings in Flash ROM */
findflash();
n = 200;
continue;
}
#else
(void)getchar();
#endif
/* enter command line */
argv = new_argv;
argc = input_cmdline(argv, MAX_ARGS);
break;
}
delay(10000);
}
putchar('\n');
howto = RB_AUTOBOOT; /* default is autoboot = 0 */
/* get boot options and determine bootname */
for (n = 1; n < argc; n++) {
if (strncmp(argv[n], "ide:", 4) == 0)
continue; /* ignore drive configuration argument */
for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) {
if (strncasecmp(argv[n], bootargs[i].name,
strlen(bootargs[i].name)) == 0) {
howto |= bootargs[i].value;
break;
}
}
if (i >= sizeof(bootargs) / sizeof(bootargs[0]))
break; /* break on first unknown string */
}
/*
* If no device name is given, we construct a list of drives
* which have valid disklabels.
*/
if (n >= argc) {
static const size_t blen = sizeof("wdN:");
n = 0;
argc = 0;
argv = alloc(MAX_UNITS * (sizeof(char *) + blen));
bname = (char *)(argv + MAX_UNITS);
for (i = 0; i < MAX_UNITS; i++) {
if (!dlabel_valid(i))
continue;
snprintf(bname, blen, "wd%d:", i);
argv[argc++] = bname;
bname += blen;
}
/* use default drive if no valid disklabel is found */
if (argc == 0) {
argc = 1;
argv[0] = BNAME_DEFAULT;
}
}
/* try to boot off kernel from the drive list */
while (n < argc) {
bname = argv[n++];
if (check_bootname(bname) == 0) {
printf("%s not a valid bootname\n", bname);
continue;
}
if ((fd = open(bname, 0)) < 0) {
if (errno == ENOENT)
printf("\"%s\" not found\n", bi_path.bootpath);
continue;
}
printf("loading \"%s\" ", bi_path.bootpath);
marks[MARK_START] = 0;
if (howto == -1) {
/* load another altboot binary and replace ourselves */
len = read(fd, (void *)0x100000, 0x1000000 - 0x100000);
if (len == -1)
goto loadfail;
close(fd);
netif_shutdown_all();
/*
* Add a /-separated list of module names to the boot list
*/
void
module_add_split(const char *name)
{
char mod_name[MAXMODNAME];
int i;
const char *mp = name;
char *ep;
while (*mp) { /* scan list of module names */
i = MAXMODNAME;
ep = mod_name;
while (--i) { /* scan for end of first name */
*ep = *mp;
if (*ep == '/') /* NUL-terminate the name */
*ep = '\0';
if (*ep == 0 ) { /* add non-empty name */
if (ep != mod_name)
module_add(mod_name);
break;
}
ep++; mp++;
}
if (*ep != 0) {
printf("module name too long\n");
return;
}
if (*mp == '/') { /* skip separator if more */
mp++;
}
}
}
/*
* Return the drive configuration for the requested channel 'ch'.
* Channel 2 is the first channel of the next IDE controller.
* 0: for no drive present on channel
* 1: for master drive present on channel, no slave
* 2: for master and slave drive present
*/
int
get_drive_config(int ch)
{
if (drive_config != NULL) {
if (strlen(drive_config) <= ch)
return 0; /* an unspecified channel is unused */
if (drive_config[ch] >= '0' && drive_config[ch] <= '2')
return drive_config[ch] - '0';
}
return -1;
}
static int
parse_cmdline(char **argv, int maxargc, char *p, char *end)
{
int argc;
argv[0] = "";
for (argc = 1; argc < maxargc && p < end; argc++) {
while (is_space(*p))
p++;
if (p >= end)
break;
argv[argc] = p;
while (!is_space(*p) && p < end)
p++;
*p++ = '\0';
}
return argc;
}
static int
is_space(char c)
{
return c > '\0' && c <= ' ';
}
#ifdef DEBUG
static void
findflash(void)
{
char buf[256];
int i, n;
unsigned char c, *p;
for (;;) {
printf("\nfind> ");
kgets(buf, sizeof(buf));
if (tolower((unsigned)buf[0]) == 'x')
break;
for (i = 0, n = 0, c = 0; buf[i]; i++) {
c <<= 4;
c |= hex2nibble(buf[i]);
if (i & 1)
buf[n++] = c;
}
printf("Searching for:");
for (i = 0; i < n; i++)
printf(" %02x", buf[i]);
printf("\n");
for (p = (unsigned char *)0xff000000;
p <= (unsigned char *)(0xffffffff-n); p++) {
for (i = 0; i < n; i++) {
if (p[i] != buf[i])
break;
}
if (i >= n)
printf("Found at %08x\n", (unsigned)p);
}
}
}
static void
sat_test(void)
{
char buf[1024];
int i, j, n, pos;
unsigned char c;
putchar('\n');
for (;;) {
do {
for (pos = 0; pos < 1024 && sat_tstch() != 0; pos++)
buf[pos] = sat_getch();
if (pos > 1023)
break;
delay(100000);
} while (sat_tstch());
for (i = 0; i < pos; i += 16) {
if ((n = i + 16) > pos)
n = pos;
for (j = 0; j < n; j++)
printf("%02x ", (unsigned)buf[i + j]);
for (; j < 16; j++)
printf(" ");
putchar('\"');
for (j = 0; j < n; j++) {
c = buf[i + j];
putchar((c >= 0x20 && c <= 0x7e) ? c : '.');
}
printf("\"\n");
}
if (buf[0] == '0' && tolower((unsigned)buf[1]) == 'x') {
for (i = 2, n = 0, c = 0; buf[i]; i++) {
c <<= 4;
c |= hex2nibble(buf[i]);
if (i & 1)
buf[n++] = c;
}
} else
n = strlen(buf);