#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.45 2026/07/14 13:37:21 thorpej Exp $");
#include "opt_m68k_arch.h"
#define _M68K_BUS_SPACE_PRIVATE
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/boot_flag.h>
#include <uvm/uvm_extern.h>
#include <sys/sysctl.h>
#include <machine/psl.h>
#include <m68k/linux_bootinfo.h>
#include <dev/cons.h>
#include <dev/mm.h>
#ifdef DDB
#include <ddb/ddb.h>
#endif
#include "gftty.h"
#if NGFTTY > 0
#include <dev/goldfish/gfttyvar.h>
#endif
void machine_init(paddr_t);
struct pmap_bootmap machine_bootmap[] = {
{ .pmbm_vaddr = VIRT68K_IO_BASE,
.pmbm_size = VIRT68K_IO_SIZE,
.pmbm_flags = PMBM_F_KEEPOUT },
{ .pmbm_vaddr = -1 },
};
static void
machine_cnattach(void (*func)(bus_space_tag_t, bus_space_handle_t),
paddr_t addr, paddr_t size)
{
extern paddr_t consdev_addr;
bus_space_tag_t bst = &m68k_simple_bus_space;
bus_space_handle_t bsh;
if (bus_space_map(bst, addr, size, 0, &bsh) == 0) {
func(bst, bsh);
}
consdev_addr = addr;
}
void
machine_init(paddr_t nextpa)
{
struct bi_record *bi __unused;
extern paddr_t msgbufpa;
#if NGFTTY > 0
bi = bootinfo_find(BI_VIRT_GF_TTY_BASE);
if (bi != NULL) {
struct bi_virt_dev *vd = bootinfo_dataptr(bi);
machine_cnattach(gftty_cnattach, vd->vd_mmio_base, 0x1000);
printf("Initialized Goldfish TTY console @ 0x%08x\n",
vd->vd_mmio_base);
}
#endif
bootinfo_startup2(nextpa);
KASSERT(MSGBUFSIZE <= 8192);
msgbufpa = 0;
machine_init_common(nextpa);
bootinfo_setup_rndseed();
char flags[32];
if (bootinfo_getarg("flags", flags, sizeof(flags))) {
for (const char *cp = flags; *cp != '\0'; cp++) {
if (*cp == 'm') {
continue;
}
BOOT_FLAG(*cp, boothowto);
}
}
}
void
consinit(void)
{
#ifdef DDB
if (boothowto & RB_KDB)
Debugger();
#endif
}
void
cpu_startup(void)
{
struct bootinfo_data *bid = bootinfo_data();
cpu_startup_common();
if (bid->bootinfo_mem_segments_ignored) {
printf("WARNING: ignored %zd bytes of memory in %d segments.\n",
bid->bootinfo_mem_segments_ignored_bytes,
bid->bootinfo_mem_segments_ignored);
}
}
void
machine_set_model(void)
{
struct bi_record *bi = bootinfo_find(BI_VIRT_QEMU_VERSION);
if (bi != NULL) {
uint32_t qvers = bootinfo_get_u32(bi);
cpu_setmodel("Qemu %d.%d.%d Virt platform",
(qvers >> 24) & 0xff,
(qvers >> 16) & 0xff,
(qvers >> 8) & 0xff);
} else {
cpu_setmodel("Nono Virt platform");
}
}
SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
{
static bool broken_rmc;
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);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_BOOL, "broken_rmc", NULL,
NULL, 0, &broken_rmc, 0,
CTL_MACHDEP, CPU_BROKEN_RMC, CTL_EOL);
}
static void
default_reset_func(void *arg, int howto)
{
printf("WARNING: No reset handler, holding here.\n\n");
for (;;) {
}
}
static void (*cpu_reset_func)(void *, int) = default_reset_func;
static void *cpu_reset_func_arg;
void
cpu_set_reset_func(void (*func)(void *, int), void *arg)
{
if (cpu_reset_func == default_reset_func && func != NULL) {
cpu_reset_func = func;
cpu_reset_func_arg = arg;
}
}
void
machine_halt(void)
{
(*cpu_reset_func)(cpu_reset_func_arg, RB_HALT);
}
void
machine_reboot(int howto, char *bootstr)
{
(*cpu_reset_func)(cpu_reset_func_arg, RB_AUTOBOOT);
}
int
nmihand(void *arg)
{
printf("NMI ignored.\n");
return 1;
}
const uint16_t ipl2psl_table[NIPL] = {
[IPL_NONE] = PSL_S | PSL_IPL0,
[IPL_SOFTCLOCK] = PSL_S | PSL_IPL1,
[IPL_SOFTBIO] = PSL_S | PSL_IPL1,
[IPL_SOFTNET] = PSL_S | PSL_IPL1,
[IPL_SOFTSERIAL] = PSL_S | PSL_IPL1,
[IPL_VM] = PSL_S | PSL_IPL5,
[IPL_SCHED] = PSL_S | PSL_IPL6,
[IPL_HIGH] = PSL_S | PSL_IPL7,
};