#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/clockintr.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/msgbuf.h>
#include <sys/syscallargs.h>
#include <sys/pledge.h>
#include <sys/exec.h>
#include <sys/sysctl.h>
#include <sys/errno.h>
#include <sys/extent.h>
#include <sys/core.h>
#include <sys/kcore.h>
#include <machine/asm.h>
#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/kcore.h>
#include <machine/reg.h>
#include <machine/trap.h>
#include <machine/m88100.h>
#include <luna88k/luna88k/isr.h>
#include <dev/cons.h>
#include <net/if.h>
#include <uvm/uvm_extern.h>
#include "ksyms.h"
#if DDB
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>
#endif
void consinit(void);
#ifdef MULTIPROCESSOR
void cpu_boot_secondary_processors(void);
#endif
void cpu_setup_secondary_processors(void);
void dumpconf(void);
void dumpsys(void);
int getcpuspeed(void);
void get_fuse_rom_data(void);
void get_nvram_data(void);
void identifycpu(void);
void luna88k_bootstrap(void);
#ifdef MULTIPROCESSOR
void luna88k_ipi_handler(struct trapframe *);
#endif
struct cpu_info *luna88k_set_cpu_number(cpuid_t);
void luna88k_vector_init(uint32_t *, uint32_t *);
char *nvram_by_symbol(char *);
void powerdown(void);
void savectx(struct pcb *);
void secondary_main(void);
void *secondary_pre_main(void);
void setlevel(u_int);
vaddr_t size_memory(void);
extern int clockintr(void *);
extern void get_autoboot_device(void);
u_int32_t int_set_val[INT_LEVEL] = {
INT_SET_LV0,
INT_SET_LV1,
INT_SET_LV2,
INT_SET_LV3,
INT_SET_LV4,
INT_SET_LV5,
INT_SET_LV6,
INT_SET_LV7
};
struct fuse_rom_byte {
u_int32_t h;
u_int32_t l;
};
#define FUSE_ROM_BYTES (FUSE_ROM_SPACE / sizeof(struct fuse_rom_byte))
char fuse_rom_data[FUSE_ROM_BYTES];
#define NNVSYM 8
#define NVSYMLEN 16
#define NVVALLEN 16
struct nvram_t {
char symbol[NVSYMLEN];
char value[NVVALLEN];
} nvram[NNVSYM];
register_t kernel_vbr;
int physmem;
struct vm_map *exec_map = NULL;
struct vm_map *phys_map = NULL;
__cpu_simple_lock_t cpu_hatch_mutex = __SIMPLELOCK_UNLOCKED;
#ifdef MULTIPROCESSOR
__cpu_simple_lock_t cpu_boot_mutex = __SIMPLELOCK_LOCKED;
unsigned int hatch_pending_count;
vaddr_t hatch_stacks[MAXCPUS - 1];
#endif
struct uvm_constraint_range dma_constraint = { 0x0, (paddr_t)-1 };
struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
char machine[] = MACHINE;
char cpu_model[120];
#if defined(DDB) || NKSYMS > 0
extern char *esym;
#endif
int machtype = LUNA_88K;
int cputyp = CPU_88100;
int cpuspeed = 33;
int sysconsole = 0;
u_int16_t dipswitch = 0;
int hwplanebits;
extern struct consdev syscons;
extern void syscnattach(int);
extern int omfb_cnattach(void);
extern void ws_cnattach(void);
vaddr_t first_addr;
extern struct user *proc0paddr;
void
consinit()
{
if (sysconsole == 0) {
syscnattach(0);
} else {
omfb_cnattach();
ws_cnattach();
}
#if defined(DDB)
db_machine_init();
ddb_init();
if (boothowto & RB_KDB)
db_enter();
#endif
}
vaddr_t
size_memory()
{
unsigned int *volatile look;
unsigned int *max;
#define PATTERN 0x5a5a5a5a
#define STRIDE (4*1024)
#define Roundup(value, stride) (((unsigned)(value) + (stride) - 1) & ~((stride)-1))
max = (void *)MAXPHYSMEM;
for (look = (void *)first_addr; look < max;
look = (int *)((unsigned)look + STRIDE)) {
unsigned save;
if (badaddr((vaddr_t)look, 4)) {
look = (int *)((int)look - STRIDE);
break;
}
save = *look;
if (*look = PATTERN, *look != PATTERN)
break;
if (*look = ~PATTERN, *look != ~PATTERN)
break;
*look = save;
}
return (trunc_page((vaddr_t)look));
}
int
getcpuspeed()
{
switch(machtype) {
case LUNA_88K:
return 25;
case LUNA_88K2:
return 33;
default:
panic("getcpuspeed: can not determine CPU speed");
}
}
void
identifycpu()
{
cpuspeed = getcpuspeed();
snprintf(cpu_model, sizeof cpu_model,
"OMRON LUNA-88K%s, %dMHz",
machtype == LUNA_88K2 ? "2" : "", cpuspeed);
}
void
cpu_startup()
{
vaddr_t minaddr, maxaddr;
get_fuse_rom_data();
if (strncmp(fuse_rom_data, "MNAME=LUNA88K+", 14) == 0) {
machtype = LUNA_88K2;
}
get_nvram_data();
get_autoboot_device();
printf("%s", version);
identifycpu();
printf("real mem = %lu (%luMB)\n", ptoa(physmem),
ptoa(physmem) / 1024 / 1024);
#ifdef DEBUG
printf("dipsw = 0x%x\n", dipswitch);
#endif
if ((0x8000 & dipswitch) == 0) {
boothowto |= RB_SINGLE;
}
if ((0x2000 & dipswitch) == 0) {
boothowto |= RB_ASKNAME;
}
if ((0x1000 & dipswitch) == 0) {
boothowto |= RB_CONFIG;
}
switch (hwplanebits) {
case 0:
case 1:
case 4:
case 8:
break;
default:
printf("unexpected frame buffer depth = %d\n", hwplanebits);
hwplanebits = 0;
break;
}
minaddr = vm_map_min(kernel_map);
exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, 0, FALSE, NULL);
printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
ptoa(uvmexp.free) / 1024 / 1024);
bufinit();
isrinit();
if (boothowto & RB_CONFIG) {
#ifdef BOOT_CONFIG
user_config();
#else
printf("kernel does not support -c; continuing..\n");
#endif
}
}
__dead void
boot(int howto)
{
if ((howto & RB_RESET) != 0)
goto doreset;
if (curproc && curproc->p_addr)
savectx(curpcb);
if (cold) {
if ((howto & RB_USERREQ) == 0)
howto |= RB_HALT;
goto haltsys;
}
boothowto = howto;
if ((howto & RB_NOSYNC) == 0) {
vfs_shutdown(curproc);
if ((howto & RB_TIMEBAD) == 0) {
resettodr();
} else {
printf("WARNING: not updating battery clock\n");
}
}
if_downall();
uvm_shutdown();
splhigh();
cold = 1;
if ((howto & RB_DUMP) != 0)
dumpsys();
haltsys:
config_suspend_all(DVACT_POWERDOWN);
if ((howto & RB_POWERDOWN) != 0) {
printf("attempting to power down...\n");
powerdown();
}
if ((howto & RB_HALT) != 0) {
printf("halted\n\n");
} else {
doreset:
*((volatile uint32_t *)RESET_CPU_ALL) = 0;
}
for (;;)
continue;
}
u_long dumpmag = 0x8fca0101;
int dumpsize = 0;
long dumplo = 0;
cpu_kcore_hdr_t cpu_kcore_hdr;
void
dumpconf(void)
{
int nblks;
if (dumpdev == NODEV ||
(nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
return;
if (nblks <= ctod(1))
return;
dumpsize = physmem;
cpu_kcore_hdr.ram_segs[0].start = 0;
cpu_kcore_hdr.ram_segs[0].size = ptoa(physmem);
cpu_kcore_hdr.cputype = cputyp;
if (dumplo < ctod(1))
dumplo = ctod(1);
if (dumpsize + 1 > dtoc(nblks - dumplo))
dumpsize = dtoc(nblks - dumplo) - 1;
if (dumplo < nblks - ctod(dumpsize) - 1)
dumplo = nblks - ctod(dumpsize) - 1;
}
void
dumpsys()
{
int maj;
int psize;
daddr_t blkno;
int (*dump)(dev_t, daddr_t, caddr_t, size_t);
int pg;
paddr_t maddr;
int error;
kcore_seg_t *kseg_p;
cpu_kcore_hdr_t *chdr_p;
char dump_hdr[dbtob(1)];
extern int msgbufmapped;
msgbufmapped = 0;
if (dumpdev == NODEV)
return;
if (dumpsize == 0) {
dumpconf();
if (dumpsize == 0)
return;
}
maj = major(dumpdev);
if (dumplo < 0) {
printf("\ndump to dev %u,%u not possible\n", maj,
minor(dumpdev));
return;
}
dump = bdevsw[maj].d_dump;
blkno = dumplo;
printf("\ndumping to dev %u,%u offset %ld\n", maj,
minor(dumpdev), dumplo);
kseg_p = (kcore_seg_t *)dump_hdr;
chdr_p = (cpu_kcore_hdr_t *)&dump_hdr[ALIGN(sizeof(*kseg_p))];
bzero(dump_hdr, sizeof(dump_hdr));
CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
kseg_p->c_size = dbtob(1) - ALIGN(sizeof(*kseg_p));
*chdr_p = cpu_kcore_hdr;
printf("dump ");
psize = (*bdevsw[maj].d_psize)(dumpdev);
if (psize == -1) {
printf("area unavailable\n");
return;
}
error = (*dump)(dumpdev, blkno++, (caddr_t)dump_hdr, dbtob(1));
if (error != 0)
goto abort;
maddr = (paddr_t)0;
for (pg = 0; pg < dumpsize; pg++) {
#define NPGMB (1024 * 1024 / PAGE_SIZE)
if (pg != 0 && (pg % NPGMB) == 0)
printf("%d ", pg / NPGMB);
#undef NPGMB
error = (*dump)(dumpdev, blkno, (caddr_t)maddr, PAGE_SIZE);
if (error == 0) {
maddr += PAGE_SIZE;
blkno += btodb(PAGE_SIZE);
} else
break;
}
abort:
switch (error) {
case 0:
printf("succeeded\n");
break;
case ENXIO:
printf("device bad\n");
break;
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("area improper\n");
break;
case EIO:
printf("i/o error\n");
break;
case EINTR:
printf("aborted from console\n");
break;
default:
printf("error %d\n", error);
break;
}
}
void
cpu_setup_secondary_processors()
{
#ifdef MULTIPROCESSOR
unsigned int cpu;
hatch_pending_count = ncpusfound - 1;
for (cpu = 0; cpu < hatch_pending_count; cpu++)
hatch_stacks[cpu] = (vaddr_t)km_alloc(USPACE, &kv_any,
&kp_zero, &kd_waitok);
#endif
__cpu_simple_unlock(&cpu_hatch_mutex);
#ifdef MULTIPROCESSOR
while (hatch_pending_count != 0)
delay(10000);
#endif
}
struct cpu_info *
luna88k_set_cpu_number(cpuid_t number)
{
struct cpu_info *ci;
static const uint32_t clock_ack[] = {
OBIO_CLOCK0,
OBIO_CLOCK1,
OBIO_CLOCK2,
OBIO_CLOCK3
};
static const uint32_t intr_mask[] = {
INT_ST_MASK0,
INT_ST_MASK1,
INT_ST_MASK2,
INT_ST_MASK3
};
static const uint32_t swi_reg[] = {
SOFT_INT0,
SOFT_INT1,
SOFT_INT2,
SOFT_INT3
};
ci = set_cpu_number(number);
ci->ci_curspl = IPL_HIGH;
ci->ci_swireg = swi_reg[number];
ci->ci_intr_mask = intr_mask[number];
ci->ci_clock_ack = clock_ack[number];
return ci;
}
#ifdef MULTIPROCESSOR
void
cpu_boot_secondary_processors()
{
__cpu_simple_unlock(&cpu_boot_mutex);
}
void *
secondary_pre_main()
{
struct cpu_info *ci;
cmmu_initialize_cpu(cmmu_cpu_number());
ci = luna88k_set_cpu_number(cmmu_cpu_number());
ci->ci_curproc = &proc0;
m88100_smp_setup(ci);
splhigh();
pmap_bootstrap_cpu(ci->ci_cpuid);
ci->ci_curpcb = (void *)hatch_stacks[hatch_pending_count - 1];
if (ci->ci_curpcb == NULL) {
printf("cpu%d: unable to get startup stack\n", ci->ci_cpuid);
hatch_pending_count--;
__cpu_simple_unlock(&cpu_hatch_mutex);
for (;;)
continue;
}
return ci->ci_curpcb;
}
void
secondary_main()
{
struct cpu_info *ci = curcpu();
cpu_configuration_print(0);
ncpus++;
clockqueue_init(&ci->ci_queue);
sched_init_cpu(ci);
ci->ci_curproc = NULL;
ci->ci_randseed = (arc4random() & 0x7fffffff) + 1;
hatch_pending_count--;
__cpu_simple_unlock(&cpu_hatch_mutex);
__cpu_simple_lock(&cpu_boot_mutex);
__cpu_simple_unlock(&cpu_boot_mutex);
set_vbr(kernel_vbr);
clockintr_cpu_init(NULL);
spl0();
set_psr(get_psr() & ~PSR_IND);
SET(ci->ci_flags, CIF_ALIVE);
sched_toidle();
}
#endif
void
luna88k_ext_int(struct trapframe *eframe)
{
struct cpu_info *ci = curcpu();
uint32_t cur_isr;
u_int level, cur_int_level, old_spl;
int unmasked = 0;
cur_isr = *(volatile uint32_t *)ci->ci_intr_mask;
old_spl = eframe->tf_mask;
cur_int_level = cur_isr >> 29;
if (cur_int_level == 0 ||
!(cur_isr & (1 << (cur_int_level + 17))))
goto out;
atomic_inc_int(&uvmexp.intrs);
#ifdef MULTIPROCESSOR
while (cur_int_level == IPL_SOFTINT) {
luna88k_ipi_handler(eframe);
cur_isr = *(volatile uint32_t *)ci->ci_intr_mask;
cur_int_level = cur_isr >> 29;
}
if (cur_int_level == 0)
goto out;
#endif
do {
level = (cur_int_level > old_spl ? cur_int_level : old_spl);
setipl(level);
if (unmasked == 0) {
set_psr(get_psr() & ~PSR_IND);
unmasked = 1;
}
switch (cur_int_level) {
case 6:
clockintr((void *)eframe);
break;
case 5:
case 4:
case 3:
if (CPU_IS_PRIMARY(ci))
isrdispatch_autovec(cur_int_level);
break;
#ifdef MULTIPROCESSOR
case 1:
set_psr(get_psr() | PSR_IND);
luna88k_ipi_handler(eframe);
set_psr(get_psr() & ~PSR_IND);
break;
#endif
default:
printf("%s: cpu%d level %d interrupt.\n",
__func__, ci->ci_cpuid, cur_int_level);
break;
}
cur_isr = *(volatile uint32_t *)ci->ci_intr_mask;
cur_int_level = cur_isr >> 29;
if ( !(cur_isr & (1 << (cur_int_level + 17))))
goto out;
} while (cur_int_level != 0);
out:
if (eframe->tf_dmt0 & DMT_VALID)
m88100_trap(T_DATAFLT, eframe);
set_psr(get_psr() | PSR_IND);
}
int
sys_sysarch(struct proc *p, void *v, register_t *retval)
{
#if 0
struct sys_sysarch_args
*uap = v;
#endif
if ((p->p_p->ps_flags & PS_PLEDGE))
return pledge_fail(p, EINVAL, 0);
return (ENOSYS);
}
int
cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
size_t newlen, struct proc *p)
{
dev_t consdev;
if (namelen != 1)
return (ENOTDIR);
switch (name[0]) {
case CPU_CONSDEV:
if (cn_tab != NULL)
consdev = cn_tab->cn_dev;
else
consdev = NODEV;
return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
sizeof consdev));
case CPU_CPUTYPE:
return (sysctl_rdint(oldp, oldlenp, newp, cputyp));
default:
return (EOPNOTSUPP);
}
}
void
luna88k_vector_init(uint32_t *bootvbr, uint32_t *vectors)
{
extern vaddr_t vector_init(uint32_t *, uint32_t *, int);
extern int kernelstart;
vector_init(bootvbr, vectors, 1);
kernel_vbr = trunc_page((vaddr_t)&kernelstart);
vector_init((uint32_t *)kernel_vbr, vectors, 0);
}
void
luna88k_bootstrap()
{
extern const struct cmmu_p cmmu8820x;
extern vaddr_t avail_start;
extern vaddr_t avail_end;
vaddr_t last_addr;
#ifndef MULTIPROCESSOR
cpuid_t master_cpu;
#endif
cmmu = &cmmu8820x;
*(volatile uint32_t *)INT_ST_MASK0 = 0;
*(volatile uint32_t *)INT_ST_MASK1 = 0;
*(volatile uint32_t *)INT_ST_MASK2 = 0;
*(volatile uint32_t *)INT_ST_MASK3 = 0;
*(volatile uint32_t *)SOFT_INT0;
*(volatile uint32_t *)SOFT_INT1;
*(volatile uint32_t *)SOFT_INT2;
*(volatile uint32_t *)SOFT_INT3;
uvmexp.pagesize = PAGE_SIZE;
uvm_setpagesize();
first_addr = round_page(first_addr);
last_addr = size_memory();
physmem = atop(last_addr);
setup_board_config();
master_cpu = cmmu_init();
(void)luna88k_set_cpu_number(master_cpu);
#ifdef MULTIPROCESSOR
m88100_smp_setup(curcpu());
#endif
SET(curcpu()->ci_flags, CIF_ALIVE | CIF_PRIMARY);
m88100_apply_patches();
proc0.p_addr = proc0paddr;
curproc = &proc0;
curpcb = &proc0paddr->u_pcb;
avail_start = first_addr;
avail_end = last_addr;
#ifdef DEBUG
printf("LUNA-88K boot: memory from 0x%lx to 0x%lx\n",
avail_start, avail_end);
#endif
uvm_page_physload(atop(avail_start), atop(avail_end),
atop(avail_start), atop(avail_end), 0);
initmsgbuf((caddr_t)pmap_steal_memory(MSGBUFSIZE, NULL, NULL),
MSGBUFSIZE);
pmap_bootstrap(0, 0x20000);
bzero((caddr_t)curpcb, USPACE);
#ifndef MULTIPROCESSOR
cpu_setup_secondary_processors();
#endif
#ifdef DEBUG
printf("leaving luna88k_bootstrap()\n");
#endif
}
struct pio {
volatile u_int8_t portA;
volatile unsigned : 24;
volatile u_int8_t portB;
volatile unsigned : 24;
volatile u_int8_t portC;
volatile unsigned : 24;
volatile u_int8_t cntrl;
volatile unsigned : 24;
};
#define PIO1_POWER 0x04
#define PIO1_ENABLE 0x01
#define PIO1_DISABLE 0x00
void
powerdown(void)
{
struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;
DELAY(100000);
p1->cntrl = (PIO1_POWER << 1) | PIO1_DISABLE;
*(volatile u_int8_t *)&p1->portC;
}
void
get_fuse_rom_data(void)
{
int i;
struct fuse_rom_byte *p = (struct fuse_rom_byte *)FUSE_ROM_ADDR;
for (i = 0; i < FUSE_ROM_BYTES; i++) {
fuse_rom_data[i] =
(char)((((p->h) >> 24) & 0x000000f0) |
(((p->l) >> 28) & 0x0000000f));
p++;
}
}
void
get_nvram_data(void)
{
int i, j;
u_int8_t *page;
char buf[NVSYMLEN], *data;
if (machtype == LUNA_88K) {
data = (char *)(NVRAM_ADDR + 0x80);
for (i = 0; i < NNVSYM; i++) {
for (j = 0; j < NVSYMLEN; j++) {
buf[j] = *data;
data += 4;
}
strlcpy(nvram[i].symbol, buf, sizeof(nvram[i].symbol));
for (j = 0; j < NVVALLEN; j++) {
buf[j] = *data;
data += 4;
}
strlcpy(nvram[i].value, buf, sizeof(nvram[i].value));
}
} else if (machtype == LUNA_88K2) {
page = (u_int8_t *)(NVRAM_ADDR_88K2 + 0x20);
for (i = 0; i < NNVSYM; i++) {
*page = (u_int8_t)i;
data = (char *)NVRAM_ADDR_88K2;
strlcpy(nvram[i].symbol, data, sizeof(nvram[i].symbol));
data = (char *)(NVRAM_ADDR_88K2 + 0x10);
strlcpy(nvram[i].value, data, sizeof(nvram[i].value));
}
}
}
char *
nvram_by_symbol(char *symbol)
{
char *value;
int i;
value = NULL;
for (i = 0; i < NNVSYM; i++) {
if (strncmp(nvram[i].symbol, symbol, NVSYMLEN) == 0) {
value = nvram[i].value;
break;
}
}
return value;
}
void
setlevel(u_int level)
{
u_int32_t set_value;
struct cpu_info *ci = curcpu();
set_value = int_set_val[level];
#ifdef MULTIPROCESSOR
if (!CPU_IS_PRIMARY(ci))
set_value &= INT_SLAVE_MASK;
#endif
ci->ci_curspl = level;
*(volatile uint32_t *)ci->ci_intr_mask = set_value;
}
int
getipl(void)
{
return (int)curcpu()->ci_curspl;
}
int
setipl(int level)
{
int curspl;
uint32_t psr;
struct cpu_info *ci = curcpu();
psr = get_psr();
set_psr(psr | PSR_IND);
curspl = (int)ci->ci_curspl;
setlevel((u_int)level);
set_psr(psr);
return curspl;
}
int
splraise(int level)
{
int curspl;
uint32_t psr;
struct cpu_info *ci = curcpu();
psr = get_psr();
set_psr(psr | PSR_IND);
curspl = (int)ci->ci_curspl;
if (curspl < (u_int)level)
setlevel((u_int)level);
set_psr(psr);
return curspl;
}
#ifdef MULTIPROCESSOR
void
m88k_send_ipi(int ipi, cpuid_t cpu)
{
struct cpu_info *ci = &m88k_cpus[cpu];
if (ci->ci_ipi & ipi)
return;
atomic_setbits_int(&ci->ci_ipi, ipi);
*(volatile uint32_t *)ci->ci_swireg = ~0;
}
void
luna88k_ipi_handler(struct trapframe *eframe)
{
struct cpu_info *ci = curcpu();
int ipi = ci->ci_ipi & (CI_IPI_DDB | CI_IPI_NOTIFY);
*(volatile uint32_t *)ci->ci_swireg;
atomic_clearbits_int(&ci->ci_ipi, ipi);
if (ipi & CI_IPI_DDB) {
#ifdef DDB
extern struct __mp_lock ddb_mp_lock;
__mp_lock(&ddb_mp_lock);
__mp_unlock(&ddb_mp_lock);
if (ci->ci_cpuid == ddb_mp_nextcpu)
db_enter();
#endif
}
if (ipi & CI_IPI_NOTIFY) {
}
}
void
m88k_broadcast_ipi(int ipi)
{
struct cpu_info *us = curcpu();
struct cpu_info *ci;
CPU_INFO_ITERATOR cii;
CPU_INFO_FOREACH(cii, ci) {
if (ci == us)
continue;
if (ISSET(ci->ci_flags, CIF_ALIVE))
m88k_send_ipi(ipi, ci->ci_cpuid);
}
}
#endif
unsigned int
cpu_rnd_messybits(void)
{
struct timespec ts;
nanotime(&ts);
return (ts.tv_nsec ^ (ts.tv_sec << 20));
}