#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.256 2024/03/05 14:15:34 thorpej Exp $");
#include "opt_ddb.h"
#include "opt_modular.h"
#define _PMAX_BUS_DMA_PRIVATE
#include <sys/param.h>
#include <sys/boot_flag.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/kcore.h>
#include <sys/kernel.h>
#include <sys/ksyms.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/cpu.h>
#include <uvm/uvm_extern.h>
#include <dev/cons.h>
#include <ufs/mfs/mfs_extern.h>
#include <mips/cache.h>
#include <mips/locore.h>
#include <mips/regnum.h>
#include <mips/psl.h>
#include <pmax/autoconf.h>
#include <pmax/dec_prom.h>
#include <pmax/sysconf.h>
#include <pmax/bootinfo.h>
#include <pmax/pmax/machdep.h>
#if NKSYMS || defined(DDB) || defined(MODULAR)
#include <mips/db_machdep.h>
#include <ddb/db_extern.h>
#endif
#include "opt_dec_3min.h"
#include "opt_dec_maxine.h"
#include "opt_dec_3maxplus.h"
#include "ksyms.h"
unsigned int ssir;
struct vm_map *phys_map = NULL;
int systype;
char *bootinfo = NULL;
int cpuspeed = 30;
intptr_t physmem_boardmax;
int mem_cluster_cnt;
phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
void mach_init(int, int32_t *, int, intptr_t, u_int, char *);
static void unimpl_bus_reset(void);
static void unimpl_cons_init(void);
static void unimpl_iointr(uint32_t, vaddr_t, uint32_t);
static void unimpl_intr_establish(device_t, void *, int,
int (*)(void *), void *);
static int unimpl_memsize(void *);
static unsigned nullwork(void);
struct platform platform = {
"iobus not set",
unimpl_bus_reset,
unimpl_cons_init,
unimpl_iointr,
unimpl_intr_establish,
unimpl_memsize,
(void *)nullwork,
};
extern void *esym;
extern struct consdev promcd;
#define ARGV(i) ((char *)(intptr_t)(argv32[i]))
void
mach_init(int argc, int32_t *argv32, int code, intptr_t cv, u_int bim, char *bip)
{
char *cp;
const char *bootinfo_msg;
int i;
char *kernend;
#if NKSYMS || defined(DDB) || defined(MODULAR)
void *ssym = 0;
struct btinfo_symtab *bi_syms;
#endif
extern char edata[], end[];
if (bim == BOOTINFO_MAGIC) {
struct btinfo_magic *bi_magic;
bootinfo = bip;
bi_magic = lookup_bootinfo(BTINFO_MAGIC);
if (bi_magic == NULL || bi_magic->magic != BOOTINFO_MAGIC)
bootinfo_msg =
"invalid magic number in bootinfo structure.\n";
else
bootinfo_msg = NULL;
}
else
bootinfo_msg = "invalid bootinfo pointer (old bootblocks?)\n";
#if NKSYMS || defined(DDB) || defined(MODULAR)
bi_syms = lookup_bootinfo(BTINFO_SYMTAB);
#ifdef EXEC_AOUT
struct exec *aout = (struct exec *)edata;
#endif
if (bi_syms != NULL) {
ssym = (void *)(intptr_t)bi_syms->ssym;
esym = (void *)(intptr_t)bi_syms->esym;
if (esym < (void *)end) {
kernend = end;
} else {
kernend = esym;
}
kernend = (void *)mips_round_page(kernend);
#if 0
memset(edata, 0, end - edata);
#endif
} else
#ifdef EXEC_AOUT
if (aout->a_midmag == 0x07018b00 && (i = aout->a_syms) != 0) {
ssym = end;
i += (*(long *)(end + i + 4) + 3) & ~3;
esym = end + i + 4;
kernend = (void *)mips_round_page(esym);
memset(edata, 0, end - edata);
} else
#endif
#endif
{
kernend = (void *)mips_round_page(end);
memset(edata, 0, kernend - edata);
}
if (code == DEC_PROM_MAGIC) {
#ifdef _LP64
for (i = 0; i < sizeof(callvec) / sizeof(void *); i++)
((intptr_t *)&callvec)[i] = ((int32_t *)cv)[i];
callv = &callvec;
#else
callv = (void *)cv;
#endif
} else {
callv = &callvec;
}
#ifdef DDB
cpu_reset_address = prom_haltbutton;
#endif
cn_tab = &promcd;
#if 0
if (bootinfo_msg != NULL)
printf(bootinfo_msg);
#else
__USE(bootinfo_msg);
#endif
uvm_md_init();
mips_vector_init(NULL, false);
pmax_bus_dma_init();
if (argc > 0 && strcmp(ARGV(0), "boot") == 0) {
argc--;
argv32++;
}
makebootdev(ARGV(0));
boothowto = RB_SINGLE;
#ifdef KADB
boothowto |= RB_KDB;
#endif
for (i = 1; i < argc; i++) {
for (cp = ARGV(i); *cp; cp++) {
switch (*cp) {
case 'a':
boothowto &= ~RB_SINGLE;
break;
case 'n':
boothowto |= RB_ASKNAME;
break;
case 'N':
boothowto &= ~RB_ASKNAME;
break;
default:
BOOT_FLAG(*cp, boothowto);
break;
}
}
}
if (boothowto & RB_MINIROOT)
kernend += round_page(mfs_initminiroot(kernend));
#if NKSYMS || defined(DDB) || defined(MODULAR)
if (esym)
ksyms_addsyms_elf((char *)esym - (char *)ssym, ssym, esym);
#endif
#ifdef DDB
if (boothowto & RB_KDB)
Debugger();
#endif
lwp0.l_addr = (struct user *)kernend;
kernend += USPACE;
mips_init_lwp0_uarea();
physmem_boardmax = MIPS_MAX_MEM_ADDR;
systype = ((prom_systype() >> 16) & 0xff);
if (systype >= nsysinit) {
platform_not_supported();
}
(*sysinit[systype].init)();
physmem = (*platform.memsize)(kernend);
for (i = 0, physmem = 0; i < mem_cluster_cnt; ++i) {
physmem += atop(mem_clusters[i].size);
}
static const struct mips_vmfreelist first8 = {
.fl_start = 0,
.fl_end = 8 * 1024 * 1024,
.fl_freelist = VM_FREELIST_FIRST8
};
mips_page_physload(MIPS_KSEG0_START, (vaddr_t)kernend,
mem_clusters, mem_cluster_cnt, &first8, 1);
mips_init_msgbuf();
pmap_bootstrap();
}
void
mips_machdep_cache_config(void)
{
if (CPUISMIPS3)
mips_cache_info.mci_sdcache_size = 1024 * 1024;
}
void
consinit(void)
{
(*platform.cons_init)();
}
void
cpu_startup(void)
{
cpu_startup_common();
}
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);
}
void
cpu_reboot(int howto, char *bootstr)
{
savectx(curpcb);
#ifdef DEBUG
if (panicstr)
stacktrace();
#endif
if (cold) {
howto |= RB_HALT;
goto haltsys;
}
if ((boothowto & RB_HALT) != 0)
howto |= RB_HALT;
boothowto = howto;
if ((howto & RB_NOSYNC) == 0) {
vfs_shutdown();
}
splhigh();
#if 0
if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
#else
if ((howto & RB_DUMP) != 0)
#endif
dumpsys();
haltsys:
doshutdownhooks();
pmf_system_shutdown(boothowto);
printf("%s\n\n", ((howto & RB_HALT) != 0) ? "halted." : "rebooting...");
prom_halt(howto & RB_HALT, bootstr);
}
int
memsize_scan(void *first)
{
int i, mem;
char *cp;
mem = btoc((paddr_t)first - MIPS_KSEG0_START);
cp = (char *)MIPS_PHYS_TO_KSEG1(mem << PGSHIFT);
while (cp < (char *)physmem_boardmax) {
int j;
if (badaddr(cp, 4))
break;
i = *(int *)cp;
j = ((int *)cp)[4];
*(int *)cp = 0xa5a5a5a5;
((int *)cp)[4] = 0x5a5a5a5a;
wbflush();
if (*(int *)cp != 0xa5a5a5a5)
break;
*(int *)cp = i;
((int *)cp)[4] = j;
cp += PAGE_SIZE;
mem++;
}
mem_clusters[0].start = 0;
mem_clusters[0].size = ctob(mem);
mem_cluster_cnt = 1;
(*platform.bus_reset)();
return (mem);
}
int
memsize_bitmap(void *first)
{
memmap *prom_memmap = (memmap *)first;
int i, mapbytes;
int segstart, curaddr, xsize, segnum;
mapbytes = prom_getbitmap(prom_memmap);
if (mapbytes == 0)
return (memsize_scan(first));
segstart = curaddr = i = segnum = 0;
xsize = prom_memmap->pagesize * 8;
while (i < mapbytes) {
while (i < mapbytes && prom_memmap->bitmap[i] == 0xff) {
++i;
curaddr += xsize;
}
if (curaddr > segstart) {
mem_clusters[segnum].start = segstart;
mem_clusters[segnum].size = curaddr - segstart;
++segnum;
}
while (i < mapbytes && prom_memmap->bitmap[i] != 0xff) {
++i;
curaddr += xsize;
}
segstart = curaddr;
}
mem_cluster_cnt = segnum;
for (i = 0; i < segnum; ++i) {
printf("segment %2d start %08lx size %08lx\n", i,
(long)mem_clusters[i].start, (long)mem_clusters[i].size);
}
return (mapbytes * 8);
}
static void
unimpl_bus_reset(void)
{
panic("sysconf.init didn't set bus_reset");
}
static void
unimpl_cons_init(void)
{
panic("sysconf.init didn't set cons_init");
}
static void
unimpl_iointr(uint32_t status, vaddr_t pc, uint32_t ipending)
{
panic("sysconf.init didn't set intr");
}
static void
unimpl_intr_establish(device_t dev, void *cookie, int level,
int (*handler)(void *), void *arg)
{
panic("sysconf.init didn't set intr_establish");
}
static int
unimpl_memsize(void *first)
{
panic("sysconf.init didn't set memsize");
}
static unsigned
nullwork(void)
{
return (0);
}
void
delay(int n)
{
DELAY(n);
}