#include "boot.h"
#include <sys/param.h>
#include <sys/boot_flag.h>
#include <sys/disklabel.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>
#include <lib/libkern/libkern.h>
#include "ofdev.h"
#include "openfirm.h"
extern void __syncicache(void *, size_t);
#ifdef DEBUG
# define DPRINTF printf
#else
# define DPRINTF while (0) printf
#endif
char bootdev[MAXBOOTPATHLEN];
extern char bootfile[MAXBOOTPATHLEN];
int boothowto;
bool floppyboot;
int ofw_version = 0;
static const char *kernels[] = { "/netbsd", "/netbsd.gz", "/netbsd.macppc", NULL };
static void
prom2boot(char *dev)
{
char *cp;
DPRINTF("%s: bootpath from OF: \"%s\"\n", __func__, dev);
cp = dev + strlen(dev) - 1;
for (; *cp; cp--) {
if (*cp == ':') {
if (ofw_version < 3) {
*cp = 0;
break;
} else {
if (cp[1] == ',') {
cp[1] = '\0';
} else {
strcpy(cp, ":0");
}
break;
}
}
}
DPRINTF("%s: bootpath patched: \"%s\"\n", __func__, dev);
}
static void
parseargs(char *str, int *howtop)
{
char *cp;
if (strcmp(str, "exit") == 0)
OF_exit();
*howtop = 0;
cp = str;
if (*cp == '-')
goto found;
for (cp = str; *cp; cp++)
if (*cp == ' ')
goto found;
return;
found:
*cp++ = 0;
while (*cp)
BOOT_FLAG(*cp++, *howtop);
}
static bool
is_floppyboot(const char *path, const char *defaultdev)
{
char dev[MAXBOOTPATHLEN];
char nam[16];
int handle, rv;
if (parsefilepath(path, dev, NULL, NULL)) {
if (dev[0] == '\0' && defaultdev != NULL)
strlcpy(dev, defaultdev, sizeof(dev));
handle = OF_finddevice(dev);
if (handle != -1) {
rv = OF_getprop(handle, "name", nam, sizeof(nam));
if (rv >= 0 &&
(strcmp(nam, "swim3") == 0 ||
strcmp(nam, "floppy") == 0))
return true;
}
if (strcmp(dev, "fd") == 0)
return true;
}
return false;
}
static void
chain(boot_entry_t entry, char *args, void *ssym, void *esym)
{
extern char end[];
int l;
#if !defined(HEAP_VARIABLE)
freeall();
#endif
l = strlen(args) + 1;
memcpy(args + l, &ssym, sizeof(ssym));
l += sizeof(ssym);
memcpy(args + l, &esym, sizeof(esym));
l += sizeof(esym);
l += sizeof(int);
OF_chain((void *) RELOC, end - (char *) RELOC, entry, args, l);
panic("chain");
}
__dead void
_rtt(void)
{
OF_exit();
}
void
main(void)
{
extern char bootprog_name[], bootprog_rev[];
char bootline[512];
char prop[32];
char *cp;
u_long marks[MARK_MAX];
u_int32_t entry;
void *ssym, *esym;
printf("\n");
printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
if (ofw_openprom != -1) {
memset(prop, 0, sizeof prop);
OF_getprop(ofw_openprom, "model", prop, sizeof prop);
for (cp = prop; *cp; cp++)
if (*cp >= '0' && *cp <= '9') {
ofw_version = *cp - '0';
break;
}
printf(">> Open Firmware version %d.x\n", ofw_version);
}
printf(">> Open Firmware running in %s-mode.\n",
ofw_real_mode ? "real" : "virtual");
if (OF_getprop(ofw_chosen, "bootpath", bootdev, sizeof bootdev) < 0 ||
OF_getprop(ofw_chosen, "bootargs", bootline, sizeof bootline) < 0) {
printf("Invalid Openfirmware environment\n");
OF_exit();
}
if (bootdev[0] == 0) {
printf("Cannot use bootpath\n");
if (ofw_options == -1 ||
OF_getprop(ofw_options, "boot-device", bootdev,
sizeof bootdev) < 0) {
printf("Invalid Openfirmware environment\n");
OF_exit();
}
printf("Using boot-device instead\n");
}
prom2boot(bootdev);
parseargs(bootline, &boothowto);
DPRINTF("bootline=%s\n", bootline);
for (;;) {
int i, loadflag;
if (boothowto & RB_ASKNAME) {
printf("Boot: ");
kgets(bootline, sizeof(bootline));
parseargs(bootline, &boothowto);
}
if (bootline[0]) {
kernels[0] = bootline;
kernels[1] = NULL;
}
for (i = 0; kernels[i]; i++) {
floppyboot = is_floppyboot(kernels[i], bootdev);
DPRINTF("Trying %s%s\n", kernels[i],
floppyboot ? " (floppyboot)" : "");
loadflag = LOAD_KERNEL;
if (floppyboot)
loadflag &= ~LOAD_BACKWARDS;
marks[MARK_START] = 0;
if (loadfile(kernels[i], marks, loadflag) >= 0)
goto loaded;
}
boothowto |= RB_ASKNAME;
}
loaded:
#ifdef __notyet__
OF_setprop(ofw_chosen, "bootpath", opened_name,
strlen(opened_name) + 1);
cp = bootline;
#else
strcpy(bootline, opened_name);
cp = bootline + strlen(bootline);
*cp++ = ' ';
#endif
*cp = '-';
if (boothowto & RB_ASKNAME)
*++cp = 'a';
if (boothowto & RB_USERCONF)
*++cp = 'c';
if (boothowto & RB_SINGLE)
*++cp = 's';
if (boothowto & RB_KDB)
*++cp = 'd';
if (*cp == '-')
#ifdef __notyet__
*cp = 0;
#else
*--cp = 0;
#endif
else
*++cp = 0;
#ifdef __notyet__
OF_setprop(ofw_chosen, "bootargs", bootline, strlen(bootline) + 1);
#endif
entry = marks[MARK_ENTRY];
ssym = (void *)marks[MARK_SYM];
esym = (void *)marks[MARK_END];
printf(" start=0x%x\n", entry);
__syncicache((void *)(uintptr_t)entry, (size_t)ssym - entry);
chain((boot_entry_t)(uintptr_t)entry, bootline, ssym, esym);
OF_exit();
}
#ifdef HAVE_CHANGEDISK_HOOK
void
changedisk_hook(struct open_file *of)
{
struct of_dev *op = of->f_devdata;
int c;
OF_call_method("eject", op->handle, 0, 0, NULL);
c = getchar();
if (c == 'q') {
printf("quit\n");
OF_exit();
}
OF_call_method("close", op->handle, 0, 0, NULL);
OF_call_method("open", op->handle, 0, 0, NULL);
}
#endif