#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.273 2025/10/13 04:04:52 thorpej Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_modular.h"
#include "opt_multiprocessor.h"
#include "opt_sparc_arch.h"
#include "scsibus.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/endian.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/device.h>
#include <sys/disk.h>
#include <sys/conf.h>
#include <sys/reboot.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/msgbuf.h>
#include <sys/boot_flag.h>
#include <sys/ksyms.h>
#include <sys/userconf.h>
#include <sys/kgdb.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <net/ether_calls.h>
#include <dev/cons.h>
#include <uvm/uvm_extern.h>
#include <machine/pcb.h>
#include <sys/bus.h>
#include <machine/promlib.h>
#include <machine/autoconf.h>
#include <machine/bootinfo.h>
#include <machine/locore.h>
#include <sparc/sparc/memreg.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <sparc/sparc/asm.h>
#include <sparc/sparc/cpuvar.h>
#include <sparc/sparc/timerreg.h>
#include <sparc/dev/cons.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pcivar.h>
#include <sparc/sparc/msiiepreg.h>
#ifdef DDB
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#include <ddb/ddbvar.h>
#endif
#include "ksyms.h"
#if !NKSYMS && !defined(DDB) && !defined(MODULAR)
void bootinfo_relocate(void *);
#endif
static const char *str2hex(const char *, int *);
static int mbprint(void *, const char *);
static void crazymap(const char *, int *);
int st_crazymap(int);
int sd_crazymap(int);
void sync_crash(void);
int mainbus_match(device_t, cfdata_t, void *);
static void mainbus_attach(device_t, device_t, void *);
struct bootpath bootpath[8];
int nbootpath;
static void bootpath_build(void);
static void bootpath_fake(struct bootpath *, const char *);
static void bootpath_print(struct bootpath *);
static struct bootpath *bootpath_store(int, struct bootpath *);
static int find_cpus(void);
char machine_model[100];
#ifdef DEBUG
#define ACDB_BOOTDEV 0x1
#define ACDB_PROBE 0x2
int autoconf_debug = 0;
#define DPRINTF(l, s) do { if (autoconf_debug & l) printf s; } while (0)
#else
#define DPRINTF(l, s)
#endif
int
matchbyname(device_t parent, cfdata_t cf, void *aux)
{
printf("%s: WARNING: matchbyname\n", cf->cf_name);
return (0);
}
static void
set_machine_model(bool late)
{
char namebuf[32];
if (!CPU_ISSUN4) {
if (late) {
KASSERT(machine_model[0] != '\0');
} else {
snprintf(machine_model, sizeof machine_model, "%s",
prom_getpropstringA(findroot(), "name", namebuf,
sizeof(namebuf)));
}
return;
}
if (late)
snprintf(machine_model, sizeof machine_model, "SUN-4/%d series",
cpuinfo.classlvl);
else
snprintf(machine_model, sizeof machine_model, "SUN-4 series");
}
static int
find_cpus(void)
{
int n;
#if defined(SUN4M) || defined(SUN4D)
int node;
#endif
cpu_arch = 7;
set_machine_model(false);
if (!CPU_ISSUN4M && !CPU_ISSUN4D)
return (1);
n = 0;
#if defined(SUN4M)
node = findroot();
for (node = firstchild(node); node; node = nextsibling(node)) {
if (strcmp(prom_getpropstring(node, "device_type"), "cpu") != 0)
continue;
if (n++ == 0)
cpu_arch = prom_getpropint(node, "sparc-version", 7);
}
#endif
#if defined(SUN4D)
node = findroot();
for (node = firstchild(node); node; node = nextsibling(node)) {
int unode;
if (strcmp(prom_getpropstring(node, "name"), "cpu-unit") != 0)
continue;
for (unode = firstchild(node); unode;
unode = nextsibling(unode)) {
if (strcmp(prom_getpropstring(unode, "device_type"),
"cpu") != 0)
continue;
if (n++ == 0)
cpu_arch = prom_getpropint(unode,
"sparc-version", 7);
}
}
#endif
return (n);
}
static const char *
str2hex(const char *str, int *vp)
{
int v, c;
for (v = 0;; v = v * 16 + c, str++) {
c = (u_char)*str;
if (c <= '9') {
if ((c -= '0') < 0)
break;
} else if (c <= 'F') {
if ((c -= 'A' - 10) < 10)
break;
} else if (c <= 'f') {
if ((c -= 'a' - 10) < 10)
break;
} else
break;
}
*vp = v;
return (str);
}
#if defined(SUN4M)
#if !defined(MSIIEP)
static void bootstrap4m(void);
#else
static void bootstrapIIep(void);
#endif
#endif
void
bootstrap(void)
{
#if NKSYMS || defined(DDB) || defined(MODULAR)
struct btinfo_symtab *bi_sym;
#endif
struct btinfo_boothowto *bi_howto;
cn_tab = &consdev_prom;
prom_init();
sparc_ncpus = find_cpus();
uvm_lwp_setuarea(&lwp0, (vaddr_t)u0);
cpuinfo.master = 1;
getcpuinfo(&cpuinfo, 0);
curlwp = &lwp0;
#if defined(SUN4M) || defined(SUN4D)
if (cpu_arch == 8) {
sparc_v8_muldiv();
}
#endif
#if !NKSYMS && !defined(DDB) && !defined(MODULAR)
bootinfo_relocate((void *)ALIGN((u_int)end));
#endif
pmap_bootstrap(cpuinfo.mmu_ncontext,
cpuinfo.mmu_nregion,
cpuinfo.mmu_nsegment);
#if !defined(MSGBUFSIZE) || MSGBUFSIZE == 8192
initmsgbuf((void *)KERNBASE, 8192);
#endif
#if defined(SUN4M)
if (CPU_ISSUN4M) {
#if !defined(MSIIEP)
bootstrap4m();
#else
bootstrapIIep();
#endif
}
#endif
#if defined(SUN4) || defined(SUN4C)
if (CPU_ISSUN4 || CPU_ISSUN4C) {
pmap_kenter_pa(INTRREG_VA,
INT_ENABLE_REG_PHYSADR | PMAP_NC | PMAP_OBIO,
VM_PROT_READ | VM_PROT_WRITE, 0);
pmap_update(pmap_kernel());
*((unsigned char *)INTRREG_VA) = 0;
}
#endif
#if NKSYMS || defined(DDB) || defined(MODULAR)
if ((bi_sym = lookup_bootinfo(BTINFO_SYMTAB)) != NULL) {
if (bi_sym->ssym < KERNBASE) {
bi_sym->ssym += KERNBASE;
bi_sym->esym += KERNBASE;
}
ksyms_addsyms_elf(bi_sym->nsym, (void*)bi_sym->ssym,
(void*)bi_sym->esym);
}
#endif
if ((bi_howto = lookup_bootinfo(BTINFO_BOOTHOWTO)) != NULL) {
boothowto = bi_howto->boothowto;
}
}
#if defined(SUN4M) && !defined(MSIIEP)
static void
bootstrap4m(void)
{
int node;
int nvaddrs, *vaddrs, vstore[10];
u_int pte;
int i;
if ((node = prom_opennode("/obio/interrupt")) == 0
&& (node = prom_finddevice("/obio/interrupt")) == 0)
panic("bootstrap: could not get interrupt "
"node from prom");
vaddrs = vstore;
nvaddrs = sizeof(vstore)/sizeof(vstore[0]);
if (prom_getprop(node, "address", sizeof(int),
&nvaddrs, &vaddrs) != 0) {
printf("bootstrap: could not get interrupt properties");
prom_halt();
}
if (nvaddrs < 2 || nvaddrs > 5) {
printf("bootstrap: cannot handle %d interrupt regs\n",
nvaddrs);
prom_halt();
}
for (i = 0; i < nvaddrs - 1; i++) {
pte = getpte4m((u_int)vaddrs[i]);
if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE) {
panic("bootstrap: PROM has invalid mapping for "
"processor interrupt register %d",i);
prom_halt();
}
pte |= PPROT_S;
setpte4m(PI_INTR_VA + (_MAXNBPG * i), pte);
}
cpuinfo.intreg_4m = (struct icr_pi *)
(PI_INTR_VA + (_MAXNBPG * CPU_MID2CPUNO(bootmid)));
pte = getpte4m((u_int)vaddrs[i]);
if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
panic("bootstrap: PROM has invalid mapping for system "
"interrupt register");
pte |= PPROT_S;
setpte4m(SI_INTR_VA, pte);
icr_si_bis(SINTR_MA);
*((u_int *)ICR_ITR) = CPU_MID2CPUNO(bootmid);
#ifdef DEBUG
#endif
}
#endif
#if defined(SUN4M) && defined(MSIIEP)
static void
bootstrapIIep(void)
{
int node;
bus_space_handle_t bh;
pcireg_t id;
if ((node = prom_opennode("/pci")) == 0
&& (node = prom_finddevice("/pci")) == 0)
panic("bootstrap: could not get pci "
"node from prom");
if (bus_space_map2(&mainbus_space_tag,
(bus_addr_t)MSIIEP_PCIC_PA,
(bus_size_t)sizeof(struct msiiep_pcic_reg),
BUS_SPACE_MAP_LINEAR,
MSIIEP_PCIC_VA, &bh) != 0)
panic("bootstrap: unable to map ms-IIep pcic registers");
id = mspcic_read_4(pcic_id);
if (PCI_VENDOR(id) != PCI_VENDOR_SUN
&& PCI_PRODUCT(id) != PCI_PRODUCT_SUN_MS_IIep)
panic("bootstrap: PCI id %08x", id);
}
#undef msiiep
#endif
static void
bootpath_build(void)
{
const char *cp;
char *pp;
struct bootpath *bp;
int fl;
memset(bootpath, 0, sizeof(bootpath));
bp = bootpath;
cp = prom_getbootpath();
switch (prom_version()) {
case PROM_OLDMON:
case PROM_OBP_V0:
if (cp != NULL)
bootpath_fake(bp, cp);
break;
case PROM_OBP_V2:
case PROM_OBP_V3:
case PROM_OPENFIRM:
while (cp != NULL && *cp == '/') {
++cp;
pp = bp->name;
while (*cp != '@' && *cp != '/' && *cp != '\0')
*pp++ = *cp++;
*pp = '\0';
#if defined(SUN4M)
if (CPU_ISSUN4M && bp == bootpath
&& strcmp(bp->name, "sbus") == 0) {
printf("bootpath_build: inserting iommu entry\n");
strcpy(bootpath[0].name, "iommu");
bootpath[0].val[0] = 0;
bootpath[0].val[1] = 0x10000000;
bootpath[0].val[2] = 0;
++nbootpath;
strcpy(bootpath[1].name, "sbus");
if (*cp == '/') {
bootpath[1].val[0] = 0;
bootpath[1].val[1] = 0x10001000;
bootpath[1].val[2] = 0;
++nbootpath;
bp = &bootpath[2];
continue;
} else
bp = &bootpath[1];
}
#endif
if (*cp == '@') {
cp = str2hex(++cp, &bp->val[0]);
if (*cp == ',')
cp = str2hex(++cp, &bp->val[1]);
if (*cp == ':') {
bp->val[2] = *++cp - 'a';
while (*++cp != '/' && *cp != '\0')
;
}
} else {
bp->val[0] = -1;
}
++bp;
++nbootpath;
}
bp->name[0] = 0;
break;
}
bootpath_print(bootpath);
cp = prom_getbootargs();
if (cp == NULL)
return;
while (*cp != '-')
if (*cp++ == '\0')
return;
for (;*++cp;) {
fl = 0;
BOOT_FLAG(*cp, fl);
if (!fl) {
printf("unknown option `%c'\n", *cp);
continue;
}
boothowto |= fl;
if (*cp == 'd') {
#if defined(KGDB)
kgdb_debug_panic = 1;
kgdb_connect(1);
#elif defined(DDB)
Debugger();
#else
printf("kernel has no debugger\n");
#endif
}
}
}
static void
bootpath_fake(struct bootpath *bp, const char *cp)
{
const char *pp;
int v0val[3];
#define BP_APPEND(BP,N,V0,V1,V2) { \
strcpy((BP)->name, N); \
(BP)->val[0] = (V0); \
(BP)->val[1] = (V1); \
(BP)->val[2] = (V2); \
(BP)++; \
nbootpath++; \
}
#if defined(SUN4)
if (CPU_ISSUN4M) {
printf("twas brillig..\n");
return;
}
#endif
pp = cp + 2;
v0val[0] = v0val[1] = v0val[2] = 0;
if (*pp == '('
&& *(pp = str2hex(++pp, &v0val[0])) == ','
&& *(pp = str2hex(++pp, &v0val[1])) == ',')
(void)str2hex(++pp, &v0val[2]);
#if defined(SUN4)
if (CPU_ISSUN4) {
char tmpname[8];
if (cp[0] == 'x') {
if (cp[1] == 'd') {
BP_APPEND(bp, "vme", -1, 0, 0);
} else {
BP_APPEND(bp, "vme", -1, 0, 0);
}
snprintf(tmpname, sizeof(tmpname), "x%cc", cp[1]);
BP_APPEND(bp, tmpname, -1, v0val[0], 0);
snprintf(tmpname, sizeof(tmpname), "x%c", cp[1]);
BP_APPEND(bp, tmpname, v0val[1], v0val[2], 0);
return;
}
if ((cp[0] == 'i' || cp[0] == 'l') && cp[1] == 'e') {
BP_APPEND(bp, "obio", -1, 0, 0);
snprintf(tmpname, sizeof(tmpname), "%c%c", cp[0], cp[1]);
BP_APPEND(bp, tmpname, -1, 0, 0);
return;
}
if (cp[0] == 's' &&
(cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
int target, lun;
switch (cpuinfo.cpu_type) {
case CPUTYP_4_200:
case CPUTYP_4_400:
BP_APPEND(bp, "vme", -1, 0, 0);
BP_APPEND(bp, "si", -1, v0val[0], 0);
break;
case CPUTYP_4_100:
BP_APPEND(bp, "obio", -1, 0, 0);
BP_APPEND(bp, "sw", -1, v0val[0], 0);
break;
case CPUTYP_4_300:
BP_APPEND(bp, "obio", -1, 0, 0);
BP_APPEND(bp, "esp", -1, v0val[0], 0);
break;
default:
panic("bootpath_fake: unknown system type %d",
cpuinfo.cpu_type);
}
if (prom_revision() > '1') {
target = v0val[1] >> 3;
lun = v0val[1] & 0x7;
} else {
target = v0val[1] >> 2;
lun = v0val[1] & 0x3;
}
snprintf(tmpname, sizeof(tmpname),
"%c%c", cp[0], cp[1]);
BP_APPEND(bp, tmpname, target, lun, v0val[2]);
return;
}
return;
}
#endif
#if defined(SUN4C)
if (cp[0] == 'f' && cp[1] == 'd') {
BP_APPEND(bp, "fd", -1, v0val[1], v0val[2]);
return;
}
if (cp[0] == 'l' && cp[1] == 'e') {
BP_APPEND(bp, "sbus", -1, 0, 0);
BP_APPEND(bp, "le", -1, v0val[0], 0);
return;
}
if (cp[0] == 's' && (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
char tmpname[8];
int target, lun;
BP_APPEND(bp, "sbus", -1, 0, 0);
BP_APPEND(bp, "esp", -1, v0val[0], 0);
if (cp[1] == 'r')
snprintf(tmpname, sizeof(tmpname), "cd");
else
snprintf(tmpname, sizeof(tmpname), "%c%c", cp[0], cp[1]);
target = v0val[1];
lun = 0;
BP_APPEND(bp, tmpname, target, lun, v0val[2]);
return;
}
#endif
#undef BP_APPEND
}
static void
bootpath_print(struct bootpath *bp)
{
printf("bootpath: ");
while (bp->name[0]) {
if (bp->val[0] == -1)
printf("/%s%x", bp->name, bp->val[1]);
else
printf("/%s@%x,%x", bp->name, bp->val[0], bp->val[1]);
if (bp->val[2] != 0)
printf(":%c", bp->val[2] + 'a');
bp++;
}
printf("\n");
}
struct bootpath *
bootpath_store(int storep, struct bootpath *bp)
{
static struct bootpath *save;
struct bootpath *retval;
retval = save;
if (storep)
save = bp;
return (retval);
}
static void
crazymap(const char *prop, int *map)
{
int i;
char propval[8+2];
if (!CPU_ISSUN4 && prom_version() < 2) {
if (prom_getoption(prop, propval, sizeof propval) != 0 ||
propval[0] == '\0' || strlen(propval) != 8) {
build_default_map:
printf("WARNING: %s map is bogus, using default\n",
prop);
for (i = 0; i < 8; ++i)
map[i] = i;
i = map[0];
map[0] = map[3];
map[3] = i;
return;
}
for (i = 0; i < 8; ++i) {
map[i] = propval[i] - '0';
if (map[i] < 0 ||
map[i] >= 8)
goto build_default_map;
}
} else {
for (i = 0; i < 8; ++i)
map[i] = i;
}
}
int
sd_crazymap(int n)
{
static int prom_sd_crazymap[8];
static int init = 0;
if (init == 0) {
crazymap("sd-targets", prom_sd_crazymap);
init = 1;
}
return prom_sd_crazymap[n];
}
int
st_crazymap(int n)
{
static int prom_st_crazymap[8];
static int init = 0;
if (init == 0) {
crazymap("st-targets", prom_st_crazymap);
init = 1;
}
return prom_st_crazymap[n];
}
void
cpu_configure(void)
{
struct pcb *pcb0;
bool userconf = (boothowto & RB_USERCONF) != 0;
sparc_softintr_init();
bootpath_build();
if (((boothowto & RB_USERCONF) != 0) && !userconf)
userconf_prompt();
#if defined(SUN4)
if (CPU_ISSUN4) {
#define MEMREG_PHYSADDR 0xf4000000
bus_space_handle_t bh;
bus_addr_t paddr = MEMREG_PHYSADDR;
if (cpuinfo.cpu_type == CPUTYP_4_100)
paddr &= ~0xf0000000;
if (obio_find_rom_map(paddr, PAGE_SIZE, &bh) != 0)
panic("configure: ROM hasn't mapped memreg!");
par_err_reg = (volatile int *)bh;
}
#endif
#if defined(SUN4C)
if (CPU_ISSUN4C) {
char *cp, buf[32];
int node = findroot();
cp = prom_getpropstringA(node, "device_type", buf, sizeof buf);
if (strcmp(cp, "cpu") != 0)
panic("PROM root device type = %s (need CPU)", cp);
}
#endif
prom_setcallback(sync_crash);
#if defined(SUN4M)
#if !defined(MSIIEP)
if (CPU_ISSUN4M)
icr_si_bic(SINTR_MA);
#else
if (CPU_ISSUN4M)
;
#endif
#endif
#if defined(SUN4) || defined(SUN4C)
if (CPU_ISSUN4 || CPU_ISSUN4C)
ienab_bis(IE_ALLIE);
#endif
if (config_rootfound("mainbus", NULL) == NULL)
panic("mainbus not configured");
pcb0 = lwp_getpcb(&lwp0);
memset(pcb0, 0, sizeof(struct pcb));
spl0();
}
void
cpu_rootconf(void)
{
struct bootpath *bp;
bp = nbootpath == 0 ? NULL : &bootpath[nbootpath-1];
if (bp == NULL)
booted_partition = 0;
else if (booted_device != bp->dev)
booted_partition = 0;
else
booted_partition = bp->val[2];
rootconf();
}
void
sync_crash(void)
{
panic("PROM sync command");
}
char *
clockfreq(int freq)
{
static char buf[10];
size_t len;
freq /= 1000;
len = snprintf(buf, sizeof(buf), "%d", freq / 1000);
freq %= 1000;
if (freq)
snprintf(buf + len, sizeof(buf) - len, ".%03d", freq);
return buf;
}
static int
mbprint(void *aux, const char *name)
{
struct mainbus_attach_args *ma = aux;
if (name)
aprint_normal("%s at %s", ma->ma_name, name);
if (ma->ma_paddr)
aprint_normal(" %saddr 0x%lx",
BUS_ADDR_IOSPACE(ma->ma_paddr) ? "io" : "",
(u_long)BUS_ADDR_PADDR(ma->ma_paddr));
if (ma->ma_pri)
aprint_normal(" ipl %d", ma->ma_pri);
return (UNCONF);
}
int
mainbus_match(device_t parent, cfdata_t cf, void *aux)
{
return (1);
}
#if defined(SUN4C) || defined(SUN4M) || defined(SUN4D)
static int prom_getprop_reg1(int, struct openprom_addr *);
static int prom_getprop_intr1(int, int *);
static int prom_getprop_address1(int, void **);
#endif
static void
mainbus_attach(device_t parent, device_t dev, void *aux)
{
struct boot_special {
const char *const dev;
#define BS_EARLY 1
#define BS_IGNORE 2
#define BS_OPTIONAL 4
unsigned int flags;
};
struct mainbus_attach_args ma;
#if defined(SUN4C) || defined(SUN4M) || defined(SUN4D)
char namebuf[32];
const char *sp = NULL;
int node0, node;
const struct boot_special *openboot_special, *ssp;
#endif
#if defined(SUN4C)
static const struct boot_special openboot_special4c[] = {
{ "memory-error", BS_EARLY },
{ "eeprom", BS_EARLY },
{ "counter-timer", BS_EARLY },
{ "auxiliary-io", BS_EARLY },
{ "aliases", BS_IGNORE },
{ "interrupt-enable", BS_IGNORE },
{ "memory", BS_IGNORE },
{ "openprom", BS_IGNORE },
{ "options", BS_IGNORE },
{ "packages", BS_IGNORE },
{ "virtual-memory", BS_IGNORE },
{ NULL, 0 }
};
#else
#define openboot_special4c ((void *)0)
#endif
#if defined(SUN4M)
static const struct boot_special openboot_special4m[] = {
{ "SUNW,sx", BS_EARLY|BS_OPTIONAL },
{ "obio", BS_EARLY|BS_OPTIONAL },
{ "pci", BS_EARLY|BS_OPTIONAL },
{ "virtual-memory", BS_IGNORE },
{ "aliases", BS_IGNORE },
{ "chosen", BS_IGNORE },
{ "memory", BS_IGNORE },
{ "openprom", BS_IGNORE },
{ "options", BS_IGNORE },
{ "packages", BS_IGNORE },
{ "udp", BS_IGNORE },
{ NULL, 0 }
};
#else
#define openboot_special4m ((void *)0)
#endif
#if defined(SUN4D)
static const struct boot_special openboot_special4d[] = {
{ "mem-unit", BS_IGNORE },
{ "boards", BS_IGNORE },
{ "openprom", BS_IGNORE },
{ "virtual-memory", BS_IGNORE },
{ "memory", BS_IGNORE },
{ "aliases", BS_IGNORE },
{ "options", BS_IGNORE },
{ "packages", BS_IGNORE },
{ NULL, 0 }
};
#else
#define openboot_special4d ((void *)0)
#endif
set_machine_model(true);
prom_getidprom();
printf(": %s: hostid %lx\n", machine_model, hostid);
bootpath_store(1, bootpath);
#if defined(SUN4)
if (CPU_ISSUN4) {
memset(&ma, 0, sizeof(ma));
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_name = "cpu";
if (config_found(dev, (void *)&ma, mbprint, CFARGS_NONE) == NULL)
panic("cpu missing");
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_name = "obio";
if (config_found(dev, (void *)&ma, mbprint, CFARGS_NONE) == NULL)
panic("obio missing");
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_name = "vme";
(void)config_found(dev, (void *)&ma, mbprint, CFARGS_NONE);
return;
}
#endif
#if defined(SUN4C) || defined(SUN4M) || defined(SUN4D)
devhandle_t selfh = device_handle(dev);
if (CPU_ISSUN4D)
openboot_special = openboot_special4d;
else if (CPU_ISSUN4M)
openboot_special = openboot_special4m;
else
openboot_special = openboot_special4c;
node0 = firstchild(findroot());
if (CPU_ISSUN4M) {
const char *cp;
int mid, bootnode = 0;
rescan:
for (node = node0; node; node = nextsibling(node)) {
cp = prom_getpropstringA(node, "device_type",
namebuf, sizeof namebuf);
if (strcmp(cp, "cpu") != 0)
continue;
mid = prom_getpropint(node, "mid", -1);
if (bootnode == 0) {
if (bootmid != 0 && mid != bootmid)
continue;
bootnode = node;
} else {
if (node == bootnode)
continue;
}
memset(&ma, 0, sizeof(ma));
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_node = node;
ma.ma_name = "cpu";
config_found(dev, (void *)&ma, mbprint,
CFARGS(.devhandle = prom_node_to_devhandle(selfh,
node)));
if (node == bootnode && bootmid != 0) {
goto rescan;
}
}
} else if (CPU_ISSUN4C) {
memset(&ma, 0, sizeof(ma));
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_node = findroot();
ma.ma_name = "cpu";
config_found(dev, (void *)&ma, mbprint,
CFARGS(.devhandle = prom_node_to_devhandle(selfh,
ma.ma_node)));
}
for (ssp = openboot_special; (sp = ssp->dev) != NULL; ssp++) {
struct openprom_addr romreg;
if (!(ssp->flags & BS_EARLY)) continue;
if ((node = findnode(node0, sp)) == 0) {
if (ssp->flags & BS_OPTIONAL) continue;
printf("could not find %s in OPENPROM\n", sp);
panic("%s", sp);
}
memset(&ma, 0, sizeof ma);
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_name = prom_getpropstringA(node, "name",
namebuf, sizeof namebuf);
ma.ma_node = node;
if (prom_getprop_reg1(node, &romreg) != 0)
continue;
ma.ma_paddr = (bus_addr_t)
BUS_ADDR(romreg.oa_space, romreg.oa_base);
ma.ma_size = romreg.oa_size;
if (prom_getprop_intr1(node, &ma.ma_pri) != 0)
continue;
if (prom_getprop_address1(node, &ma.ma_promvaddr) != 0)
continue;
if (config_found(dev, (void *)&ma, mbprint,
CFARGS(.devhandle =
prom_node_to_devhandle(selfh,
node))) == NULL) {
if (ssp->flags & BS_OPTIONAL) continue;
panic("%s", sp);
}
}
for (node = node0; node; node = nextsibling(node)) {
const char *cp;
struct openprom_addr romreg;
DPRINTF(ACDB_PROBE, ("Node: %x", node));
#if defined(SUN4M)
if (CPU_ISSUN4M) {
if (strcmp(prom_getpropstringA(node, "device_type",
namebuf, sizeof namebuf),
"cpu") == 0)
continue;
}
#endif
cp = prom_getpropstringA(node, "name", namebuf, sizeof namebuf);
DPRINTF(ACDB_PROBE, (" name %s\n", namebuf));
for (ssp = openboot_special; (sp = ssp->dev) != NULL; ssp++) {
if (!(ssp->flags & (BS_EARLY|BS_IGNORE))) continue;
if (strcmp(cp, sp) == 0)
break;
}
if (sp != NULL)
continue;
memset(&ma, 0, sizeof ma);
ma.ma_bustag = &mainbus_space_tag;
ma.ma_dmatag = &mainbus_dma_tag;
ma.ma_name = prom_getpropstringA(node, "name",
namebuf, sizeof namebuf);
ma.ma_node = node;
#if defined(SUN4M)
if (CPU_ISSUN4M && strcmp(ma.ma_name, "sbus") == 0) {
printf("mainbus_attach: sbus node under root on sun4m - assuming iommu\n");
ma.ma_name = "iommu";
ma.ma_paddr = (bus_addr_t)BUS_ADDR(0, 0x10000000);
ma.ma_size = 0x300;
ma.ma_pri = 0;
ma.ma_promvaddr = 0;
config_found(dev, (void *)&ma, mbprint,
CFARGS(.devhandle = prom_node_to_devhandle(selfh,
node)));
continue;
}
#endif
if (prom_getprop_reg1(node, &romreg) != 0)
continue;
ma.ma_paddr = BUS_ADDR(romreg.oa_space, romreg.oa_base);
ma.ma_size = romreg.oa_size;
if (prom_getprop_intr1(node, &ma.ma_pri) != 0)
continue;
if (prom_getprop_address1(node, &ma.ma_promvaddr) != 0)
continue;
config_found(dev, (void *)&ma, mbprint,
CFARGS(.devhandle = prom_node_to_devhandle(selfh, node)));
}
#endif
}
CFATTACH_DECL_NEW(mainbus, 0, mainbus_match, mainbus_attach, NULL, NULL);
#if defined(SUN4C) || defined(SUN4M) || defined(SUN4D)
int
prom_getprop_reg1(int node, struct openprom_addr *rrp)
{
int error, n;
struct openprom_addr *rrp0 = NULL;
char buf[32];
error = prom_getprop(node, "reg", sizeof(struct openprom_addr),
&n, &rrp0);
if (error != 0) {
if (error == ENOENT &&
strcmp(prom_getpropstringA(node, "device_type", buf, sizeof buf),
"hierarchical") == 0) {
memset(rrp, 0, sizeof(struct openprom_addr));
error = 0;
}
return (error);
}
*rrp = rrp0[0];
free(rrp0, M_DEVBUF);
return (0);
}
int
prom_getprop_intr1(int node, int *ip)
{
int error, n;
struct rom_intr *rip = NULL;
error = prom_getprop(node, "intr", sizeof(struct rom_intr),
&n, &rip);
if (error != 0) {
if (error == ENOENT) {
*ip = 0;
error = 0;
}
return (error);
}
*ip = rip[0].int_pri & 0xf;
free(rip, M_DEVBUF);
return (0);
}
int
prom_getprop_address1(int node, void **vpp)
{
int error, n;
void **vp = NULL;
error = prom_getprop(node, "address", sizeof(uint32_t), &n, &vp);
if (error != 0) {
if (error == ENOENT) {
*vpp = 0;
error = 0;
}
return (error);
}
*vpp = vp[0];
free(vp, M_DEVBUF);
return (0);
}
#endif
#ifdef RASTERCONSOLE
int
romgetcursoraddr(int **rowp, int **colp)
{
char buf[100];
if (prom_version() < 2 || prom_revision() < 0x00020009)
snprintf(buf, sizeof(buf),
"' line# >body >user %lx ! ' column# >body >user %lx !",
(u_long)rowp, (u_long)colp);
else
snprintf(buf, sizeof(buf),
"stdout @ is my-self addr line# %lx ! addr column# %lx !",
(u_long)rowp, (u_long)colp);
*rowp = *colp = NULL;
prom_interpret(buf);
return (*rowp == NULL || *colp == NULL);
}
#endif
#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsiconf.h>
#include <sparc/sparc/iommuvar.h>
#define BUSCLASS_NONE 0
#define BUSCLASS_MAINBUS 1
#define BUSCLASS_IOMMU 2
#define BUSCLASS_OBIO 3
#define BUSCLASS_SBUS 4
#define BUSCLASS_VME 5
#define BUSCLASS_XDC 6
#define BUSCLASS_XYC 7
#define BUSCLASS_FDC 8
#define BUSCLASS_PCIC 9
#define BUSCLASS_PCI 10
static int bus_class(device_t);
static const char *bus_compatible(const char *);
static int instance_match(device_t, void *, struct bootpath *);
static void nail_bootdev(device_t, struct bootpath *);
static struct {
const char *name;
int class;
} bus_class_tab[] = {
{ "mainbus", BUSCLASS_MAINBUS },
{ "obio", BUSCLASS_OBIO },
{ "iommu", BUSCLASS_IOMMU },
{ "sbus", BUSCLASS_SBUS },
{ "xbox", BUSCLASS_SBUS },
{ "dma", BUSCLASS_SBUS },
{ "esp", BUSCLASS_SBUS },
{ "espdma", BUSCLASS_SBUS },
{ "isp", BUSCLASS_SBUS },
{ "ledma", BUSCLASS_SBUS },
{ "lebuffer", BUSCLASS_SBUS },
{ "vme", BUSCLASS_VME },
{ "si", BUSCLASS_VME },
{ "sw", BUSCLASS_OBIO },
{ "xdc", BUSCLASS_XDC },
{ "xyc", BUSCLASS_XYC },
{ "fdc", BUSCLASS_FDC },
{ "mspcic", BUSCLASS_PCIC },
{ "pci", BUSCLASS_PCI },
};
static struct {
const char *bpname;
const char *cfname;
} dev_compat_tab[] = {
{ "espdma", "dma" },
{ "SUNW,fas", "esp" },
{ "QLGC,isp", "isp" },
{ "PTI,isp", "isp" },
{ "ptisp", "isp" },
{ "SUNW,fdtwo", "fdc" },
{ "network", "hme" },
{ "SUNW,hme", "hme" },
{ "SUNW,qfe", "hme" },
};
static const char *
bus_compatible(const char *bpname)
{
int i;
for (i = sizeof(dev_compat_tab)/sizeof(dev_compat_tab[0]); i-- > 0;) {
if (strcmp(bpname, dev_compat_tab[i].bpname) == 0)
return (dev_compat_tab[i].cfname);
}
return (bpname);
}
static int
bus_class(device_t dev)
{
int i, class;
class = BUSCLASS_NONE;
if (dev == NULL)
return (class);
for (i = sizeof(bus_class_tab)/sizeof(bus_class_tab[0]); i-- > 0;) {
if (device_is_a(dev, bus_class_tab[i].name)) {
class = bus_class_tab[i].class;
break;
}
}
if (CPU_ISSUN4M && class == BUSCLASS_OBIO)
class = BUSCLASS_SBUS;
return (class);
}
static int
sparc_ether_get_mac_address(device_t dev, devhandle_t call_handle, void *v)
{
struct ether_get_mac_address_args *args = v;
int node;
if (devhandle_type(call_handle) == DEVHANDLE_TYPE_OPENBOOT) {
node = prom_devhandle_to_node(call_handle);
} else {
node = 0;
}
prom_getether(node, args->enaddr);
return 0;
}
SYSDFLT_DEVICE_CALL_REGISTER(ETHER_GET_MAC_ADDRESS_STR,
sparc_ether_get_mac_address)
int
instance_match(device_t dev, void *aux, struct bootpath *bp)
{
struct mainbus_attach_args *ma;
struct sbus_attach_args *sa;
struct iommu_attach_args *iom;
struct pcibus_attach_args *pba;
struct pci_attach_args *pa;
switch (bus_class(device_parent(dev))) {
case BUSCLASS_MAINBUS:
ma = aux;
DPRINTF(ACDB_BOOTDEV, ("instance_match: mainbus device, "
"want space %#x addr %#x have space %#x addr %#llx\n",
bp->val[0], bp->val[1], (int)BUS_ADDR_IOSPACE(ma->ma_paddr),
(unsigned long long)BUS_ADDR_PADDR(ma->ma_paddr)));
if ((u_long)bp->val[0] == BUS_ADDR_IOSPACE(ma->ma_paddr) &&
(bus_addr_t)(u_long)bp->val[1] ==
BUS_ADDR_PADDR(ma->ma_paddr))
return (1);
break;
case BUSCLASS_SBUS:
sa = aux;
DPRINTF(ACDB_BOOTDEV, ("instance_match: sbus device, "
"want slot %#x offset %#x have slot %#x offset %#x\n",
bp->val[0], bp->val[1], sa->sa_slot, sa->sa_offset));
if ((uint32_t)bp->val[0] == sa->sa_slot &&
(uint32_t)bp->val[1] == sa->sa_offset)
return (1);
break;
case BUSCLASS_IOMMU:
iom = aux;
DPRINTF(ACDB_BOOTDEV, ("instance_match: iommu device, "
"want space %#x pa %#x have space %#x pa %#x\n",
bp->val[0], bp->val[1], iom->iom_reg[0].oa_space,
iom->iom_reg[0].oa_base));
if ((uint32_t)bp->val[0] == iom->iom_reg[0].oa_space &&
(uint32_t)bp->val[1] == iom->iom_reg[0].oa_base)
return (1);
break;
case BUSCLASS_XDC:
case BUSCLASS_XYC:
{
struct xxxx_attach_args { int driveno; } *aap = aux;
DPRINTF(ACDB_BOOTDEV,
("instance_match: x[dy]c device, want drive %#x have %#x\n",
bp->val[0], aap->driveno));
if (aap->driveno == bp->val[0])
return (1);
}
break;
case BUSCLASS_PCIC:
pba = aux;
DPRINTF(ACDB_BOOTDEV, ("instance_match: pci bus "
"want bus %d pa %#x have bus %d pa %#lx\n",
bp->val[0], bp->val[1], pba->pba_bus, MSIIEP_PCIC_PA));
if ((int)bp->val[0] == pba->pba_bus
&& (bus_addr_t)bp->val[1] == MSIIEP_PCIC_PA)
return (1);
break;
case BUSCLASS_PCI:
pa = aux;
DPRINTF(ACDB_BOOTDEV, ("instance_match: pci device "
"want dev %d function %d have dev %d function %d\n",
bp->val[0], bp->val[1], pa->pa_device, pa->pa_function));
if ((u_int)bp->val[0] == pa->pa_device
&& (u_int)bp->val[1] == pa->pa_function)
return (1);
break;
default:
break;
}
if (bp->val[0] == -1 && bp->val[1] == device_unit(dev))
return (1);
return (0);
}
void
nail_bootdev(device_t dev, struct bootpath *bp)
{
if (bp->dev != NULL)
panic("device_register: already got a boot device: %s",
device_xname(bp->dev));
booted_device = bp->dev = dev;
bootpath_store(1, NULL);
}
void
device_register(device_t dev, void *aux)
{
struct bootpath *bp = bootpath_store(0, NULL);
const char *bpname;
if (bp == NULL)
return;
bpname = bus_compatible(bp->name);
DPRINTF(ACDB_BOOTDEV,
("\n%s: device_register: dvname %s(%s) bpname %s(%s)\n",
device_xname(dev), device_cfdata(dev)->cf_name,
device_xname(dev), bpname, bp->name));
if (!device_is_a(dev, bpname))
return;
if (bus_class(dev) != BUSCLASS_NONE) {
if (instance_match(dev, aux, bp) != 0) {
if (device_is_a(dev, "fdc")) {
strcpy(bootpath[nbootpath].name, "fd");
nbootpath++;
}
booted_device = bp->dev = dev;
bootpath_store(1, bp + 1);
DPRINTF(ACDB_BOOTDEV, ("\t-- found bus controller %s\n",
device_xname(dev)));
return;
}
} else if (device_class(dev) == DV_IFNET) {
if (instance_match(dev, aux, bp) != 0) {
nail_bootdev(dev, bp);
DPRINTF(ACDB_BOOTDEV, ("\t-- found ethernet controller %s\n",
device_xname(dev)));
return;
}
} else if (device_is_a(dev, "sd") ||
device_is_a(dev, "cd")) {
#if NSCSIBUS > 0
struct scsipibus_attach_args *sa = aux;
struct scsipi_periph *periph = sa->sa_periph;
struct scsipi_channel *chan = periph->periph_channel;
struct scsibus_softc *sbsc =
device_private(device_parent(dev));
u_int target = bp->val[0];
u_int lun = bp->val[1];
if ((bp-1)->dev != device_parent(sbsc->sc_dev))
return;
if (target >= chan->chan_ntargets || lun >= chan->chan_nluns) {
printf("SCSI disk bootpath component not accepted: "
"target %u; lun %u\n", target, lun);
return;
}
if (CPU_ISSUN4 && device_is_a(dev, "sd") &&
target == 0 &&
scsipi_lookup_periph(chan, target, lun) == NULL) {
target = 3;
lun = 0;
}
if (CPU_ISSUN4C && device_is_a(dev, "sd"))
target = sd_crazymap(target);
if (periph->periph_target == target &&
periph->periph_lun == lun) {
nail_bootdev(dev, bp);
DPRINTF(ACDB_BOOTDEV, ("\t-- found [cs]d disk %s\n",
device_xname(dev)));
return;
}
#endif
} else if (device_is_a(dev, "xd") ||
device_is_a(dev, "xy")) {
if (instance_match(dev, aux, bp) != 0) {
nail_bootdev(dev, bp);
DPRINTF(ACDB_BOOTDEV, ("\t-- found x[dy] disk %s\n",
device_xname(dev)));
return;
}
} else if (device_is_a(dev, "fd")) {
nail_bootdev(dev, bp);
DPRINTF(ACDB_BOOTDEV, ("\t-- found floppy drive %s\n",
device_xname(dev)));
return;
} else {
if (instance_match(dev, aux, bp) != 0) {
nail_bootdev(dev, bp);
return;
}
}
}
void *
lookup_bootinfo(int type)
{
struct btinfo_common *bt;
char *help = bootinfo;
if (help == NULL)
return (NULL);
do {
bt = (struct btinfo_common *)help;
if (bt->type == type)
return ((void *)help);
help += bt->next;
} while (bt->next != 0 &&
(size_t)help < (size_t)bootinfo + BOOTINFO_SIZE);
return (NULL);
}
#if !NKSYMS && !defined(DDB) && !defined(MODULAR)
void
bootinfo_relocate(void *newloc)
{
int bi_size;
struct btinfo_common *bt;
char *cp, *dp;
if (bootinfo == NULL) {
kernel_top = newloc;
return;
}
bi_size = sizeof(struct btinfo_common);
cp = bootinfo;
do {
bt = (struct btinfo_common *)cp;
bi_size += bt->next;
cp += bt->next;
} while (bt->next != 0 &&
(size_t)cp < (size_t)bootinfo + BOOTINFO_SIZE);
if ((int)bootinfo - (int)newloc < bi_size)
return;
cp = bootinfo;
dp = newloc;
do {
bt = (struct btinfo_common *)cp;
memcpy(dp, cp, bt->next);
cp += bt->next;
dp += bt->next;
} while (bt->next != 0 &&
(size_t)cp < (size_t)bootinfo + BOOTINFO_SIZE);
bt = (struct btinfo_common *)dp;
bt->next = bt->type = 0;
bootinfo = newloc;
kernel_top = (char *)newloc + ALIGN(bi_size);
}
#endif