#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.158 2026/06/10 21:24:11 andvar Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_execfmt.h"
#include "opt_cputype.h"
#include "opt_mips_cache.h"
#include "opt_modular.h"
#define __INTR_PRIVATE
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/intr.h>
#include <sys/mbuf.h>
#include <sys/msgbuf.h>
#include <sys/device.h>
#include <sys/exec.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <sys/kcore.h>
#include <sys/boot_flag.h>
#include <sys/ksyms.h>
#include <sys/cpu.h>
#include <uvm/uvm_extern.h>
#include <mips/locore.h>
#include <machine/reg.h>
#include <machine/psl.h>
#include <machine/autoconf.h>
#include <machine/machtype.h>
#include <machine/sysconf.h>
#include <machine/bootinfo.h>
#include <mips/cache.h>
#include <mips/cache_r5k.h>
#ifdef ENABLE_MIPS4_CACHE_R10K
#include <mips/cache_r10k.h>
#endif
#include <sgimips/dev/int2reg.h>
#include <sgimips/dev/crimevar.h>
#include <sgimips/sgimips/arcemu.h>
#include <dev/arcbios/arcbios.h>
#include <dev/arcbios/arcbiosvar.h>
#include "ksyms.h"
#if NKSYMS || defined(DDB) || defined(MODULAR) || defined(KGDB)
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#include <sys/exec_elf.h>
#endif
#include "mcclock_mace.h"
#include "crime.h"
#if NMCCLOCK_MACE > 0
void mcclock_poweroff(void);
#endif
struct sgimips_intrhand intrtab[NINTR];
struct vm_map *phys_map = NULL;
int mach_type = 0;
int mach_subtype = 0;
int mach_boardrev = 0;
int arcsmem;
int ncpus;
#define IPL2SPL_TABLE_COMMON \
[IPL_NONE] = 0, \
[IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0, \
[IPL_SOFTNET] = MIPS_SOFT_INT_MASK, \
[IPL_DDB] = MIPS_INT_MASK, \
[IPL_HIGH] = MIPS_INT_MASK
#if defined(MIPS1)
static const struct ipl_sr_map sgi_ip6_ipl_sr_map = {
.sr_bits = {
IPL2SPL_TABLE_COMMON,
[IPL_VM] = MIPS_INT_MASK_1|MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK,
[IPL_SCHED] = MIPS_INT_MASK_4|MIPS_INT_MASK_2|
MIPS_INT_MASK_1|MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK,
},
};
static const struct ipl_sr_map sgi_ip12_ipl_sr_map = {
.sr_bits = {
IPL2SPL_TABLE_COMMON,
[IPL_VM] = MIPS_INT_MASK_2|MIPS_INT_MASK_1|MIPS_INT_MASK_0|
MIPS_SOFT_INT_MASK,
[IPL_SCHED] = MIPS_INT_MASK_4|MIPS_INT_MASK_3|MIPS_INT_MASK_2|
MIPS_INT_MASK_1|MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK,
},
};
#endif
#if defined(MIPS3)
static const struct ipl_sr_map sgi_ip2x_ipl_sr_map = {
.sr_bits = {
IPL2SPL_TABLE_COMMON,
[IPL_VM] = MIPS_INT_MASK_1|MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK,
[IPL_SCHED] = MIPS_INT_MASK,
},
};
static const struct ipl_sr_map sgi_ip3x_ipl_sr_map = {
.sr_bits = {
IPL2SPL_TABLE_COMMON,
[IPL_VM] = MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK,
[IPL_SCHED] = MIPS_INT_MASK_5|MIPS_INT_MASK_0|MIPS_SOFT_INT_MASK,
},
};
#endif
phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
int mem_cluster_cnt;
#if defined(INDY_R4600_CACHE)
extern void ip22_sdcache_disable(void);
extern void ip22_sdcache_enable(void);
#endif
#if defined(MIPS3)
extern void mips3_clock_intr(vaddr_t, uint32_t, uint32_t);
#endif
void mach_init(int, int32_t *, uintptr_t, int32_t);
void sgimips_count_cpus(struct arcbios_component *,
struct arcbios_treewalk_context *);
#ifdef KGDB
void kgdb_port_init(void);
void kgdb_connect(int);
#endif
void mips_machdep_find_l2cache(struct arcbios_component *comp, struct arcbios_treewalk_context *atc);
static void unimpl_bus_reset(void);
static void unimpl_cons_init(void);
static void *unimpl_intr_establish(int, int, int (*)(void *), void *);
static void unimpl_intr(vaddr_t, uint32_t, uint32_t);
static unsigned long nulllong(void);
static void nullvoid(void);
void ddb_trap_hook(int where);
static int badaddr_workaround(void *, size_t);
struct platform platform = {
.badaddr = badaddr_workaround,
.bus_reset = unimpl_bus_reset,
.cons_init = unimpl_cons_init,
.intr_establish = unimpl_intr_establish,
.clkread = nulllong,
.watchdog_reset = nullvoid,
.watchdog_disable = nullvoid,
.watchdog_enable = nullvoid,
.intr0 = unimpl_intr,
.intr1 = unimpl_intr,
.intr2 = unimpl_intr,
.intr3 = unimpl_intr,
.intr4 = unimpl_intr,
.intr5 = unimpl_intr
};
extern u_int32_t ssir;
extern char kernel_text[], edata[], end[];
uint8_t *bootinfo;
static uint8_t bi_buf[BOOTINFO_SIZE];
static const char *bootinfo_msg = NULL;
#define ARCS_VECTOR MIPS_PHYS_TO_KSEG0(0x00001000)
void
mach_init(int argc, int32_t argv32[], uintptr_t magic, int32_t bip32)
{
paddr_t first, last;
vsize_t size;
void *bip = (void *)(intptr_t)bip32;
struct arcbios_mem *mem;
const char *cpufreq, *osload;
char *bootpath = NULL;
vaddr_t kernend;
u_int i;
int rv;
#if NKSYMS || defined(DDB) || defined(MODULAR)
int nsym = 0;
char *ssym = NULL;
char *esym = NULL;
struct btinfo_symtab *bi_syms;
#endif
#ifdef _LP64
char *argv[20];
if (argc >= __arraycount(argv))
panic("too many args");
for (i = 0; i < argc; i++) {
argv[i] = (void *)(intptr_t)argv32[i];
}
#else
char **argv = (void *)argv32;
#endif
if (arcbios_init(ARCS_VECTOR) == 1) {
#ifdef _LP64
panic("no ARCS firmware");
#else
if (magic == BOOTINFO_MAGIC)
arcemu_init(NULL);
else
arcemu_init((const char **)magic);
#endif
}
cpu_setmodel("%s", arcbios_system_identifier);
mips_vector_init(NULL, false);
uvm_md_init();
if (magic == BOOTINFO_MAGIC && bip != NULL) {
struct btinfo_magic *bi_magic;
struct btinfo_bootpath *bi_path;
memcpy(bi_buf, bip, BOOTINFO_SIZE);
bootinfo = bi_buf;
bi_magic = lookup_bootinfo(BTINFO_MAGIC);
if (bi_magic != NULL && bi_magic->magic == BOOTINFO_MAGIC) {
bootinfo_msg = "bootinfo found.\n";
bi_path = lookup_bootinfo(BTINFO_BOOTPATH);
if (bi_path != NULL)
bootpath = bi_path->bootpath;
} else
bootinfo_msg =
"invalid magic number in bootinfo structure.\n";
} else
bootinfo_msg = "no bootinfo found. (old bootblocks?)\n";
#if NKSYMS || defined(DDB) || defined(MODULAR)
bi_syms = lookup_bootinfo(BTINFO_SYMTAB);
if (bi_syms != NULL) {
nsym = bi_syms->nsym;
ssym = (char *)bi_syms->ssym;
esym = (char *)bi_syms->esym;
kernend = mips_round_page(esym);
} else
#endif
{
kernend = mips_round_page(end);
}
cpufreq = arcbios_GetEnvironmentVariable("cpufreq");
if (cpufreq == 0)
panic("no $cpufreq");
curcpu()->ci_cpu_freq = strtoul(cpufreq, NULL, 10) * 1000000;
curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / (2 * hz);
curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / (2 * 1000000);
for (i = 0; arcbios_system_identifier[i] != '\0'; i++) {
if (mach_type == 0 &&
arcbios_system_identifier[i] >= '0' &&
arcbios_system_identifier[i] <= '9') {
mach_type = strtoul(&arcbios_system_identifier[i],
NULL, 10);
break;
}
}
if (mach_type <= 0)
panic("invalid architecture");
if (mach_type == MACH_SGI_IP22) {
i = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd9858);
if (i & 0x01)
mach_subtype = MACH_SGI_IP22_FULLHOUSE;
else
mach_subtype = MACH_SGI_IP22_GUINNESS;
}
if (bootpath != NULL)
makebootdev(bootpath);
else {
if (argc > 1 && strchr(argv[1], '=') != 0)
makebootdev(argv[1]);
if (argc > 0 && argv[0] != NULL) {
makebootdev(argv[0]);
booted_partition = 0;
}
}
osload = arcbios_GetEnvironmentVariable("OSLoadPartition");
if (osload != NULL)
makebootdev(osload);
for (i = 0; i < argc; i++) {
if (strncmp(argv[i], "OSLoadPartition=", 15) == 0)
makebootdev(argv[i] + 16);
}
for (i = 0; i < argc; i++) {
if (strncmp(argv[i], "SystemPartition", 15) == 0)
makebootdev(argv[i] + 16);
}
boothowto = RB_SINGLE;
osload = arcbios_GetEnvironmentVariable("OSLoadOptions");
if (osload != NULL && strcmp(osload, "auto") == 0)
boothowto &= ~RB_SINGLE;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "OSLoadOptions=auto") == 0)
boothowto &= ~RB_SINGLE;
}
for (i = 0; i < argc; i++) {
if (mach_type < MACH_SGI_IP20 && bootinfo == NULL &&
strcmp(argv[i], "-a") == 0)
continue;
if (argv[i][0] == '-') {
rv = 0;
BOOT_FLAG(argv[i][1], rv);
if (rv == 0) {
printf("Unexpected option '%s' ignored",
argv[i]);
} else {
boothowto |= rv;
}
}
}
#ifdef DEBUG
boothowto |= AB_DEBUG;
#endif
aprint_debug("argc = %d\n", argc);
for (i = 0; i < argc; i++)
aprint_debug("argv[%d] = %s\n", i, argv[i]);
#if NKSYMS || defined(DDB) || defined(MODULAR)
if (esym)
ksyms_addsyms_elf(nsym, ssym, esym);
#endif
#if defined(KGDB) || defined(DDB)
db_trap_callback = ddb_trap_hook;
#ifdef DDB
if (boothowto & RB_KDB)
Debugger();
#endif
#ifdef KGDB
kgdb_port_init();
if (boothowto & RB_KDB)
kgdb_connect(0);
#endif
#endif
switch (mach_type) {
#if defined(MIPS1)
case MACH_SGI_IP6 | MACH_SGI_IP10:
platform.intr3 = mips1_fpu_intr;
ipl_sr_map = sgi_ip6_ipl_sr_map;
break;
case MACH_SGI_IP12:
i = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd0000);
mach_boardrev = (i & 0x7000) >> 12;
if ((i & 0x8000) == 0) {
if (mach_boardrev < 7)
mach_subtype = MACH_SGI_IP12_4D_3X;
else
mach_subtype = MACH_SGI_IP12_VIP12;
} else {
if (mach_boardrev < 6)
mach_subtype = MACH_SGI_IP12_HP1;
else
mach_subtype = MACH_SGI_IP12_HPLC;
}
ipl_sr_map = sgi_ip12_ipl_sr_map;
platform.intr0 = mips1_fpu_intr;
break;
#endif
#if defined(MIPS3)
case MACH_SGI_IP20:
i = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x1fbd0000);
mach_boardrev = (i & 0x7000) >> 12;
ipl_sr_map = sgi_ip2x_ipl_sr_map;
platform.intr5 = mips3_clock_intr;
break;
case MACH_SGI_IP22:
ipl_sr_map = sgi_ip2x_ipl_sr_map;
platform.intr5 = mips3_clock_intr;
break;
case MACH_SGI_IP30:
ipl_sr_map = sgi_ip3x_ipl_sr_map;
platform.intr5 = mips3_clock_intr;
break;
case MACH_SGI_IP32:
ipl_sr_map = sgi_ip3x_ipl_sr_map;
platform.intr5 = mips3_clock_intr;
break;
#endif
default:
panic("IP%d architecture not supported", mach_type);
break;
}
physmem = arcsmem = 0;
mem_cluster_cnt = 0;
mem = NULL;
#ifdef DEBUG
i = 0;
mem = NULL;
do {
if ((mem = arcbios_GetMemoryDescriptor(mem)) != NULL) {
i++;
printf("Mem block %d: type %d, "
"base 0x%04"PRIx32", size 0x%04"PRIx32"\n",
i, mem->Type, mem->BasePage, mem->PageCount);
}
} while (mem != NULL);
#endif
mem = NULL;
for (i = 0; mem_cluster_cnt < VM_PHYSSEG_MAX; i++) {
mem = arcbios_GetMemoryDescriptor(mem);
if (mem == NULL)
break;
first = round_page(mem->BasePage * ARCBIOS_PAGESIZE);
last = trunc_page(first + mem->PageCount * ARCBIOS_PAGESIZE);
size = last - first;
switch (mem->Type) {
case ARCBIOS_MEM_FreeContiguous:
case ARCBIOS_MEM_FreeMemory:
case ARCBIOS_MEM_LoadedProgram:
mem_clusters[mem_cluster_cnt].start = first;
mem_clusters[mem_cluster_cnt].size = size;
mem_cluster_cnt++;
break;
case ARCBIOS_MEM_FirmwareTemporary:
case ARCBIOS_MEM_FirmwarePermanent:
arcsmem += btoc(size);
break;
case ARCBIOS_MEM_ExceptionBlock:
case ARCBIOS_MEM_SystemParameterBlock:
case ARCBIOS_MEM_BadMemory:
break;
default:
panic("unknown memory descriptor %d type %d",
i, mem->Type);
}
physmem += btoc(size);
}
if (mem_cluster_cnt == 0)
panic("no free memory descriptors found");
mips_page_physload((vaddr_t)kernel_text - PAGE_SIZE, (vaddr_t)kernend,
mem_clusters, mem_cluster_cnt, NULL, 0);
bootinfo = NULL;
sgimips_bus_dma_init();
arcbios_tree_walk(sgimips_count_cpus, NULL);
mips_init_msgbuf();
pmap_bootstrap();
mips_init_lwp0_uarea();
}
void
sgimips_count_cpus(struct arcbios_component *node,
struct arcbios_treewalk_context *atc)
{
switch (node->Class) {
case COMPONENT_CLASS_ProcessorClass:
if (node->Type == COMPONENT_TYPE_CPU)
ncpus++;
break;
default:
break;
}
}
void
cpu_startup(void)
{
vaddr_t minaddr, maxaddr;
char pbuf[9];
#ifdef BOOTINFO_DEBUG
if (bootinfo_msg)
printf(bootinfo_msg);
#endif
printf("%s%s", copyright, version);
format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
printf("total memory = %s\n", pbuf);
format_bytes(pbuf, sizeof(pbuf), ctob(arcsmem));
printf("(%s reserved for ARCS)\n", pbuf);
minaddr = 0;
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, false, NULL);
format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
printf("avail memory = %s\n", pbuf);
}
int waittime = -1;
void
cpu_reboot(int howto, char *bootstr)
{
savectx(curpcb);
if (cold) {
howto |= RB_HALT;
goto haltsys;
}
if (boothowto & RB_HALT)
howto |= RB_HALT;
boothowto = howto;
if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) {
waittime = 0;
vfs_shutdown();
}
(void)(*platform.watchdog_disable)();
splhigh();
if (howto & RB_DUMP)
dumpsys();
haltsys:
doshutdownhooks();
pmf_system_shutdown(boothowto);
if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
mips_cp0_status_write(mips_cp0_status_read() |
MIPS_SR_COP_1_BIT);
printf("powering off...\n\n");
delay(500000);
#if NMCCLOCK_MACE > 0
if (mach_type == MACH_SGI_IP32) {
mcclock_poweroff();
} else
#endif
arcbios_PowerDown();
printf("WARNING: powerdown failed\n");
}
if (howto & RB_HALT) {
printf("halting...\n\n");
arcbios_EnterInteractiveMode();
}
printf("rebooting...\n\n");
#if NCRIME > 0
if (mach_type == MACH_SGI_IP32) {
crime_reboot();
} else
#endif
arcbios_Reboot();
for (;;);
}
void delay(unsigned long n)
{
register int __N = curcpu()->ci_divisor_delay * n;
do {
__asm("addiu %0,%1,-1" : "=r" (__N) : "0" (__N));
} while (__N > 0);
}
static int
badaddr_workaround(void *addr, size_t size)
{
int i, bad;
for (i = bad = 0; i < 100; i++) {
if (badaddr(addr, size))
bad++;
}
return (bad != 0);
}
static void
unimpl_bus_reset(void)
{
panic("target init didn't set bus_reset");
}
static void
unimpl_cons_init(void)
{
panic("target init didn't set cons_init");
}
static void *
unimpl_intr_establish(int level, int ipl, int (*handler) (void *), void *arg)
{
panic("target init didn't set intr_establish");
return NULL;
}
static void
unimpl_intr(vaddr_t pc, uint32_t status, uint32_t pending)
{
printf("spurious interrupt pending %#x\n", pending);
}
static unsigned long
nulllong(void)
{
printf("nulllong\n");
return (0);
}
static void
nullvoid(void)
{
printf("nullvoid\n");
return;
}
void *
lookup_bootinfo(int type)
{
struct btinfo_common *bt;
uint8_t *bip;
if (bootinfo == NULL)
return NULL;
bip = bootinfo;
do {
bt = (struct btinfo_common *)bip;
if (bt->type == type)
return (void *)bt;
bip += bt->next;
} while (bt->next != 0 &&
bt->next < BOOTINFO_SIZE &&
(size_t)bip < (size_t)bootinfo + BOOTINFO_SIZE);
return NULL;
}
#if defined(DDB) || defined(KGDB)
void ddb_trap_hook(int where)
{
switch (where) {
case 1:
(void)(*platform.watchdog_disable)();
break;
case 0:
(void)(*platform.watchdog_enable)();
break;
}
}
#endif
void mips_machdep_cache_config(void)
{
arcbios_tree_walk(mips_machdep_find_l2cache, NULL);
switch (MIPS_PRID_IMPL(mips_options.mips_cpu_id)) {
#if defined(INDY_R4600_CACHE)
case MIPS_R4600:
mips_cache_info.mci_sdcache_size = 0;
mips_cache_info.mci_sdcache_line_size = 0;
ip22_sdcache_disable();
break;
#endif
#if defined(MIPS3)
case MIPS_R5000:
case MIPS_RM5200:
r5k_enable_sdcache();
break;
#endif
}
}
void
mips_machdep_find_l2cache(struct arcbios_component *comp, struct arcbios_treewalk_context *atc)
{
struct mips_cache_info * const mci = &mips_cache_info;
device_t self = atc->atc_cookie;
if (comp->Class != COMPONENT_CLASS_CacheClass)
return;
switch (comp->Type) {
case COMPONENT_TYPE_SecondaryICache:
panic("%s: split L2 cache", device_xname(self));
case COMPONENT_TYPE_SecondaryDCache:
case COMPONENT_TYPE_SecondaryCache:
mci->mci_sdcache_size = COMPONENT_KEY_Cache_CacheSize(comp->Key);
mci->mci_sdcache_line_size =
COMPONENT_KEY_Cache_LineSize(comp->Key);
mci->mci_sdcache_ways = 1;
break;
}
}