#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.154 2026/04/28 03:29:11 thorpej Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_modular.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/device.h>
#include <sys/mbuf.h>
#include <sys/msgbuf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/mount.h>
#include <sys/exec.h>
#include <sys/core.h>
#include <sys/kcore.h>
#include <sys/vnode.h>
#include <sys/syscallargs.h>
#include <sys/ksyms.h>
#include <sys/module.h>
#include <sys/cpu.h>
#ifdef KGDB
#include <sys/kgdb.h>
#endif
#include <uvm/uvm_extern.h>
#include <sys/sysctl.h>
#include <dev/cons.h>
#include <dev/mm.h>
#include <machine/cpu.h>
#include <machine/dvma.h>
#include <machine/idprom.h>
#include <machine/kcore.h>
#include <machine/reg.h>
#include <machine/pcb.h>
#include <machine/psl.h>
#include <machine/pte.h>
#include <machine/mon.h>
#if defined(DDB)
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#endif
#include <sun3/sun3/machdep.h>
#include "ksyms.h"
extern char kernel_text[];
extern char etext[];
const vaddr_t kernbase = KERNBASE3X;
const vaddr_t kern_end = KERN_END3X;
extern void *msgbufaddr;
vaddr_t vmmap;
u_char cpu_machine_id = 0;
const char *cpu_string = NULL;
int cpu_has_vme = 0;
int has_iocache = 0;
vaddr_t dumppage;
int delay_divisor = delay_divisor_est(33);
char kernel_arch[16] = "sun3x";
static void initcpu(void);
void
consinit(void)
{
cninit();
#if NKSYMS || defined(DDB) || defined(MODULAR)
{
extern int nsym;
extern char *ssym, *esym;
ksyms_addsyms_elf(nsym, ssym, esym);
}
#endif
if (boothowto & RB_KDB) {
#ifdef KGDB
kgdb_connect(1);
#else
Debugger();
#endif
}
}
void
cpu_startup(void)
{
enable_fpu(1);
dumppage = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_WIRED);
if (dumppage == 0)
panic("startup: alloc dumppage");
cpu_startup_common();
vmmap = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
UVM_KMF_VAONLY | UVM_KMF_WAITVA);
dvma_init();
initcpu();
if (fputype == FPU_NONE) {
enable_fpu(0);
}
}
void
machine_set_model(void)
{
u_char machtype = identity_prom.idp_machtype;
if ((machtype & IDM_ARCH_MASK) != IDM_ARCH_SUN3X) {
printf("Bad IDPROM arch!\n");
sunmon_abort();
}
cpu_machine_id = machtype;
switch (cpu_machine_id) {
case ID_SUN3X_80:
cpu_string = "80";
cpuspeed_khz = 20000;
delay_divisor = delay_divisor_est(20);
cpu_has_vme = false;
break;
case ID_SUN3X_470:
cpu_string = "470";
cpuspeed_khz = 33000;
delay_divisor = delay_divisor_est(33);
cpu_has_vme = true;
break;
default:
printf("unknown sun3x model\n");
sunmon_abort();
}
sun68k_set_model();
}
#if 0
static int
sysctl_machdep_root_device(SYSCTLFN_ARGS)
{
struct sysctlnode node = *rnode;
node.sysctl_data = some permutation on root_device;
node.sysctl_size = strlen(root_device) + 1;
return (sysctl_lookup(SYSCTLFN_CALL(&node)));
}
static int
sysctl_machdep_booted_kernel(SYSCTLFN_ARGS)
{
struct sysctlnode node = *rnode;
node.sysctl_data = some permutation on booted_kernel;
node.sysctl_size = strlen(booted_kernel) + 1;
return (sysctl_lookup(SYSCTLFN_CALL(&node)));
}
#endif
SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
{
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "machdep", NULL,
NULL, 0, NULL, 0,
CTL_MACHDEP, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRUCT, "console_device", NULL,
sysctl_consdev, 0, NULL, sizeof(dev_t),
CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
#if 0
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "root_device", NULL,
sysctl_machdep_root_device, 0, NULL, 0,
CTL_MACHDEP, CPU_ROOT_DEVICE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "booted_kernel", NULL,
sysctl_machdep_booted_kernel, 0, NULL, 0,
CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL);
#endif
}
void
machine_halt(void)
{
sunmon_halt();
}
void
machine_reboot(int howto, char *user_bootstr)
{
static char bootstr[128];
char *p;
if (user_bootstr != NULL) {
strlcpy(bootstr, user_bootstr, sizeof(bootstr));
} else {
p = bootstr;
*p = '\0';
if (howto & (RB_KDB|RB_ASKNAME|RB_SINGLE)) {
*p++ = ' ';
*p++ = '-';
if (howto & RB_KDB)
*p++ = 'd';
if (howto & RB_ASKNAME)
*p++ = 'a';
if (howto & RB_SINGLE)
*p++ = 's';
*p = '\0';
}
}
sunmon_reboot(bootstr);
}
uint32_t dumpmag = 0x8fca0101;
int dumpsize = 0;
long dumplo = 0;
#define DUMP_EXTRA 1
void
cpu_dumpconf(void)
{
int devblks;
int dumpblks;
if (dumpdev == NODEV)
return;
devblks = bdev_size(dumpdev);
if (devblks <= ctod(1))
return;
devblks &= ~(ctod(1) - 1);
dumpsize = physmem;
dumpblks = ctod(physmem + DUMP_EXTRA);
dumplo = devblks - dumpblks;
if (dumplo < ((long)ctod(1))) {
dumplo = ctod(1);
dumpsize = dtoc(devblks - dumplo) - DUMP_EXTRA;
}
}
struct pcb dumppcb;
void
dumpsys(void)
{
const struct bdevsw *dsw;
kcore_seg_t *kseg_p;
cpu_kcore_hdr_t *chdr_p;
struct sun3x_kcore_hdr *sh;
phys_ram_seg_t *crs_p;
char *vaddr;
paddr_t paddr;
int psize, todo, seg, segsz;
daddr_t blkno;
int error = 0;
if (dumpdev == NODEV)
return;
dsw = bdevsw_lookup(dumpdev);
if (dsw == NULL || dsw->d_psize == NULL)
return;
if (dumpsize == 0)
cpu_dumpconf();
if (dumplo <= 0) {
printf("\ndump to dev %u,%u not possible\n",
major(dumpdev), minor(dumpdev));
return;
}
savectx(&dumppcb);
psize = bdev_size(dumpdev);
if (psize == -1) {
printf("dump area unavailable\n");
return;
}
printf("\ndumping to dev %u,%u offset %ld\n",
major(dumpdev), minor(dumpdev), dumplo);
blkno = dumplo;
todo = dumpsize;
vaddr = (char *)dumppage;
memset(vaddr, 0, PAGE_SIZE);
kseg_p = (kcore_seg_t *)vaddr;
chdr_p = (cpu_kcore_hdr_t *)(kseg_p + 1);
sh = &chdr_p->un._sun3x;
CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
kseg_p->c_size = (ctob(DUMP_EXTRA) - sizeof(*kseg_p));
strncpy(chdr_p->name, kernel_arch, sizeof(chdr_p->name));
chdr_p->page_size = PAGE_SIZE;
chdr_p->kernbase = KERNBASE3X;
pmap_kcore_hdr(sh);
error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE);
if (error)
goto fail;
blkno += btodb(PAGE_SIZE);
vaddr = (char *)vmmap;
for (seg = 0; seg < SUN3X_NPHYS_RAM_SEGS; seg++) {
crs_p = &sh->ram_segs[seg];
paddr = crs_p->start;
segsz = crs_p->size;
while (todo && (segsz > 0)) {
if ((todo & 0xf) == 0)
printf_nolog("\r%4d", todo);
pmap_kenter_pa(vmmap, paddr | PMAP_NC, VM_PROT_READ, 0);
pmap_update(pmap_kernel());
error = (*dsw->d_dump)(dumpdev, blkno, vaddr,
PAGE_SIZE);
pmap_kremove(vmmap, PAGE_SIZE);
pmap_update(pmap_kernel());
if (error)
goto fail;
paddr += PAGE_SIZE;
segsz -= PAGE_SIZE;
blkno += btodb(PAGE_SIZE);
todo--;
}
}
printf("\rdump succeeded\n");
return;
fail:
printf(" dump error=%d\n", error);
}
static void
initcpu(void)
{
#ifdef HAVECACHE
cache_enable();
#endif
}
bool
mm_md_direct_mapped_phys(paddr_t paddr, vaddr_t *vaddr)
{
extern paddr_t avail_start;
if (paddr >= avail_start)
return false;
*vaddr = KERNBASE3X + paddr;
return true;
}
int
mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled)
{
if ((vaddr_t)ptr < SUN3X_PROM_BASE || (vaddr_t)ptr > SUN3X_MONEND) {
*handled = false;
return 0;
}
*handled = true;
if ((prot & VM_PROT_WRITE) == 0)
return 0;
if ((vaddr_t)ptr >= SUN3X_MONDATA &&
(vaddr_t)ptr < SUN3X_MONDATA + PAGE_SIZE)
return 0;
return EFAULT;
}