#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.81 2026/04/08 04:06:40 thorpej Exp $");
#include "opt_md.h"
#include "opt_ddb.h"
#include "opt_kgdb.h"
#include "opt_modular.h"
#include "biconsdev.h"
#include "debug_hpc.h"
#include "hd64465if.h"
#include "opt_kloader.h"
#include "opt_kloader_kernel_path.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/lwp.h>
#include <sys/reboot.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/kcore.h>
#include <sys/boot_flag.h>
#include <sys/ksyms.h>
#include <sys/module.h>
#include <sys/cpu.h>
#include <uvm/uvm_extern.h>
#include <ufs/mfs/mfs_extern.h>
#include <sh3/cpu.h>
#include <sh3/exception.h>
#include <sh3/cache.h>
#include <sh3/clock.h>
#include <sh3/intcreg.h>
#include <sh3/proc.h>
#ifdef KGDB
#include <sys/kgdb.h>
#endif
#include "ksyms.h"
#if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB)
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#include <sys/exec_elf.h>
#endif
#include <dev/cons.h>
#include <dev/md.h>
#include <machine/bootinfo.h>
#include <machine/platid.h>
#include <machine/platid_mask.h>
#ifdef KLOADER
#include <machine/kloader.h>
#endif
#include <machine/autoconf.h>
#include <machine/intr.h>
#include <machine/pcb.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsmount.h>
#include <dev/hpc/apm/apmvar.h>
#include <hpcsh/dev/hd6446x/hd6446xintcvar.h>
#include <hpcsh/dev/hd6446x/hd6446xintcreg.h>
#include <hpcsh/dev/hd64465/hd64465var.h>
#ifdef DEBUG
#define DPRINTF_ENABLE
#define DPRINTF_DEBUG machdep_debug
#endif
#include <machine/debug.h>
#define SH_CS3_START 0x0c000000
#define SH_CS3_END (SH_CS3_START + 0x04000000)
#define SH7709_CS3_BANK0_START 0x0c000000
#define SH7709_CS3_BANK0_END (SH7709_CS3_BANK0_START + 0x02000000)
#define SH7709_CS3_BANK1_START 0x0e000000
#define SH7709_CS3_BANK1_END (SH7709_CS3_BANK1_START + 0x02000000)
char machine[] = MACHINE;
char machine_arch[] = MACHINE_ARCH;
static int mem_cluster_init(paddr_t);
static void mem_cluster_load(void);
static void __find_dram_shadow(paddr_t, paddr_t);
#ifdef NARLY_MEMORY_PROBE
static int __check_dram(paddr_t, paddr_t);
#endif
int mem_cluster_cnt;
phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
static struct bootinfo bootinfo_storage;
struct bootinfo *bootinfo = &bootinfo_storage;
void (*__sleep_func)(void *);
void *__sleep_ctx;
extern void main(void) __attribute__((__noreturn__));
void machine_startup(int, char *[], struct bootinfo *)
__attribute__((__noreturn__));
#ifdef KLOADER
#if !defined(KLOADER_KERNEL_PATH)
#define KLOADER_KERNEL_PATH "/netbsd"
#endif
static const char kernel_path[] = KLOADER_KERNEL_PATH;
#endif
void
machine_startup(int argc, char *argv[], struct bootinfo *bi)
{
extern char edata[], end[];
vaddr_t kernend;
size_t symbolsize;
int i;
char *p;
#ifdef KLOADER
struct kloader_bootinfo kbi;
#endif
symbolsize = 0;
#if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB)
if (memcmp(&end, ELFMAG, SELFMAG) == 0) {
Elf_Ehdr *eh = (void *)end;
Elf_Shdr *sh = (void *)(end + eh->e_shoff);
for(i = 0; i < eh->e_shnum; i++, sh++)
if (sh->sh_offset > 0 &&
(sh->sh_offset + sh->sh_size) > symbolsize)
symbolsize = sh->sh_offset + sh->sh_size;
}
#endif
memset(edata, 0, end - edata);
memcpy(&bootinfo_storage, bi, sizeof(struct bootinfo));
if (bootinfo->magic == BOOTINFO_MAGIC) {
platid.dw.dw0 = bootinfo->platid_cpu;
platid.dw.dw1 = bootinfo->platid_machine;
}
if (platid_match(&platid, &platid_mask_CPU_SH_3))
sh_cpu_init(CPU_ARCH_SH3, CPU_PRODUCT_7709A);
else if (platid_match(&platid, &platid_mask_CPU_SH_4))
sh_cpu_init(CPU_ARCH_SH4, CPU_PRODUCT_7750);
#ifndef RTC_OFFSET
if (rtc_offset == 0
&& bootinfo->timezone > (-12*60)
&& bootinfo->timezone <= (12*60))
rtc_offset = bootinfo->timezone;
#endif
kernend = (vaddr_t)sh3_round_page(end + symbolsize);
makebootdev("wd0");
boothowto = 0;
for (i = 1; i < argc; i++) {
char *cp = argv[i];
switch (*cp) {
case 'b':
p = cp + 2;
if (strcmp(p, "nfs") == 0)
rootfstype = MOUNT_NFS;
else
makebootdev(p);
break;
default:
BOOT_FLAG(*cp, boothowto);
break;
}
}
if (boothowto & RB_MINIROOT) {
size_t fssz;
fssz = sh3_round_page(mfs_initminiroot((void *)kernend));
#ifdef MEMORY_DISK_DYNAMIC
md_root_setconf((void *)kernend, fssz);
#endif
kernend += fssz;
}
consinit();
#ifdef HPC_DEBUG_LCD
dbg_lcd_test();
#endif
#ifdef KLOADER
kloader_bootinfo_set(&kbi, argc, argv, bootinfo, true);
#endif
physmem = mem_cluster_init(SH3_P1SEG_TO_PHYS(kernend));
_DPRINTF("total memory = %dMbyte\n", (int)(sh3_ptob(physmem) >> 20));
mem_cluster_load();
sh_proc0_init();
pmap_bootstrap();
#if NKSYMS || defined(MODULAR) || defined(DDB) || defined(KGDB)
if (symbolsize) {
ksyms_addsyms_elf(symbolsize, &end, end + symbolsize);
_DPRINTF("symbol size = %d byte\n", symbolsize);
}
#endif
#ifdef DDB
if (boothowto & RB_KDB)
Debugger();
#endif
#ifdef KGDB
if (boothowto & RB_KDB) {
if (kgdb_dev == NODEV) {
printf("no kgdb console.\n");
} else {
kgdb_debug_init = 1;
kgdb_connect(1);
}
}
#endif
__asm volatile(
"jmp @%0;"
"mov %1, sp"
:: "r"(main),"r"(lwp0.l_md.md_pcb->pcb_sf.sf_r7_bank));
for (;;)
continue;
}
void
cpu_startup(void)
{
cpu_setmodel("%s", platid_name(&platid));
sh_startup();
}
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);
}
void
machine_sleep(void)
{
if (__sleep_func != NULL)
__sleep_func(__sleep_ctx);
}
void
machine_standby(void)
{
}
void
cpu_reboot(int howto, char *bootstr)
{
if (curlwp)
savectx(curpcb);
if (cold) {
howto |= RB_HALT;
goto haltsys;
}
if ((boothowto & RB_HALT) != 0) {
howto |= RB_HALT;
}
#ifdef KLOADER
if ((howto & RB_HALT) == 0) {
if ((howto & RB_STRING) != 0)
kloader_reboot_setup(bootstr);
else
kloader_reboot_setup(kernel_path);
}
#endif
boothowto = howto;
if ((howto & RB_NOSYNC) == 0) {
vfs_shutdown();
}
splhigh();
#if notyet
if (howto & RB_DUMP)
dumpsys();
#endif
haltsys:
doshutdownhooks();
pmf_system_shutdown(boothowto);
if ((howto & RB_HALT) != 0) {
printf("halted.\n");
} else {
#ifdef KLOADER
kloader_reboot();
#endif
}
#if NHD64465IF > 0
hd64465_shutdown();
#endif
cpu_reset();
for (;;)
continue;
}
static int
mem_cluster_init(paddr_t addr)
{
phys_ram_seg_t *seg;
int npages, i;
mem_clusters[0].start = SH_CS3_START;
mem_clusters[0].size = addr - SH_CS3_START;
mem_cluster_cnt = 1;
#ifdef SH3
if (CPU_IS_SH3) {
__find_dram_shadow(addr, SH7709_CS3_BANK0_END);
__find_dram_shadow(SH7709_CS3_BANK1_START,
SH7709_CS3_BANK1_END);
}
#endif
#ifdef SH4
if (CPU_IS_SH4) {
__find_dram_shadow(addr, SH_CS3_END);
}
#endif
_DPRINTF("mem_cluster_cnt = %d\n", mem_cluster_cnt);
npages = 0;
for (i = 0, seg = mem_clusters; i < mem_cluster_cnt; i++, seg++) {
_DPRINTF("mem_clusters[%d] = {0x%lx+0x%lx <0x%lx}", i,
(paddr_t)seg->start, (paddr_t)seg->size,
(paddr_t)seg->start + (paddr_t)seg->size);
npages += sh3_btop(seg->size);
#ifdef NARLY_MEMORY_PROBE
if (i == 0) {
_DPRINTF(" don't check.\n");
continue;
}
if (__check_dram((paddr_t)seg->start, (paddr_t)seg->start +
(paddr_t)seg->size) != 0)
panic("D-RAM check failed.");
#else
_DPRINTF("\n");
#endif
}
return (npages);
}
static void
mem_cluster_load(void)
{
paddr_t start, end;
psize_t size;
int i;
sh_dcache_wbinv_all();
for (i = 1; i < mem_cluster_cnt; i++) {
start = (paddr_t)mem_clusters[i].start;
size = (psize_t)mem_clusters[i].size;
_DPRINTF("loading 0x%lx,0x%lx\n", start, size);
memset((void *)SH3_PHYS_TO_P1SEG(start), 0, size);
end = atop(start + size);
start = atop(start);
uvm_page_physload(start, end, start, end, VM_FREELIST_DEFAULT);
}
sh_dcache_wbinv_all();
}
static void
__find_dram_shadow(paddr_t start, paddr_t end)
{
vaddr_t page, startaddr, endaddr;
int x;
_DPRINTF("search D-RAM from 0x%08lx for 0x%08lx\n", start, end);
startaddr = SH3_PHYS_TO_P2SEG(start);
endaddr = SH3_PHYS_TO_P2SEG(end);
page = startaddr;
x = random();
*(volatile int *)(page + 0) = x;
*(volatile int *)(page + 4) = ~x;
if (*(volatile int *)(page + 0) != x ||
*(volatile int *)(page + 4) != ~x)
return;
for (page += PAGE_SIZE; page < endaddr; page += PAGE_SIZE) {
if (*(volatile int *)(page + 0) == x &&
*(volatile int *)(page + 4) == ~x) {
goto memend_found;
}
}
page -= PAGE_SIZE;
*(volatile int *)(page + 0) = x;
*(volatile int *)(page + 4) = ~x;
if (*(volatile int *)(page + 0) != x ||
*(volatile int *)(page + 4) != ~x)
return;
memend_found:
KASSERT(mem_cluster_cnt < VM_PHYSSEG_MAX);
mem_clusters[mem_cluster_cnt].start = start;
mem_clusters[mem_cluster_cnt].size = page - startaddr;
if (mem_cluster_cnt == 1)
mem_clusters[1].size -= mem_clusters[0].size;
mem_cluster_cnt++;
}
#ifdef NARLY_MEMORY_PROBE
static int
__check_dram(paddr_t start, paddr_t end)
{
uint8_t *page;
int i, x;
_DPRINTF(" checking...");
for (; start < end; start += PAGE_SIZE) {
page = (uint8_t *)SH3_PHYS_TO_P2SEG (start);
x = random();
for (i = 0; i < PAGE_SIZE; i += 4)
*(volatile int *)(page + i) = (x ^ i);
for (i = 0; i < PAGE_SIZE; i += 4)
if (*(volatile int *)(page + i) != (x ^ i))
goto bad;
x = random();
for (i = 0; i < PAGE_SIZE; i += 4)
*(volatile int *)(page + i) = (x ^ i);
for (i = 0; i < PAGE_SIZE; i += 4)
if (*(volatile int *)(page + i) != (x ^ i))
goto bad;
}
_DPRINTF("success.\n");
return (0);
bad:
_DPRINTF("failed.\n");
return (1);
}
#endif
void
intc_intr(int ssr, int spc, int ssp)
{
struct intc_intrhand *ih;
int evtcode;
uint16_t r;
curcpu()->ci_data.cpu_nintr++;
evtcode = _reg_read_4(CPU_IS_SH3 ? SH7709_INTEVT2 : SH4_INTEVT);
ih = EVTCODE_IH(evtcode);
KDASSERT(ih->ih_func);
r = _reg_read_2(HD6446X_NIRR);
splx(ih->ih_level);
if (evtcode == SH_INTEVT_TMU0_TUNI0) {
struct clockframe cf;
cf.spc = spc;
cf.ssr = ssr;
cf.ssp = ssp;
(*ih->ih_func)(&cf);
__dbg_heart_beat(HEART_BEAT_RED);
} else if (evtcode ==
(CPU_IS_SH3 ? SH7709_INTEVT2_IRQ4 : SH_INTEVT_IRL11)) {
struct hd6446x_intrhand *hh;
int cause;
cause = r & hd6446x_ienable;
if (cause == 0) {
printf("masked HD6446x interrupt 0x%04x\n",
r & ~hd6446x_ienable);
_reg_write_2(HD6446X_NIRR, 0x0000);
return;
}
hh = &hd6446x_intrhand[ffs(cause) - 1];
hd6446x_intr_resume(hh->hh_ipl);
KDASSERT(hh->hh_func != NULL);
(*hh->hh_func)(hh->hh_arg);
__dbg_heart_beat(HEART_BEAT_GREEN);
} else {
(*ih->ih_func)(ih->ih_arg);
__dbg_heart_beat(HEART_BEAT_BLUE);
}
}