Home | History | Annotate | Line # | Download | only in powerpc
      1 /*	$NetBSD: powerpc_machdep.c,v 1.89 2026/04/08 04:06:41 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
      5  * Copyright (C) 1995, 1996 TooLs GmbH.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by TooLs GmbH.
     19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 __KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.89 2026/04/08 04:06:41 thorpej Exp $");
     36 
     37 #ifdef _KERNEL_OPT
     38 #include "opt_altivec.h"
     39 #include "opt_ddb.h"
     40 #include "opt_modular.h"
     41 #include "opt_multiprocessor.h"
     42 #include "opt_ppcarch.h"
     43 #include "opt_ppcopts.h"
     44 #endif
     45 
     46 #include <sys/param.h>
     47 #include <sys/conf.h>
     48 #include <sys/disklabel.h>
     49 #include <sys/exec.h>
     50 #include <sys/kauth.h>
     51 #include <sys/pool.h>
     52 #include <sys/proc.h>
     53 #include <sys/signal.h>
     54 #include <sys/sysctl.h>
     55 #include <sys/ucontext.h>
     56 #include <sys/cpu.h>
     57 #include <sys/module.h>
     58 #include <sys/device.h>
     59 #include <sys/pcu.h>
     60 #include <sys/atomic.h>
     61 #include <sys/kmem.h>
     62 #include <sys/xcall.h>
     63 #include <sys/ipi.h>
     64 #include <sys/kcore.h>
     65 
     66 #include <dev/mm.h>
     67 
     68 #include <powerpc/fpu.h>
     69 #include <powerpc/pcb.h>
     70 #include <powerpc/psl.h>
     71 #include <powerpc/userret.h>
     72 #if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
     73 #include <powerpc/altivec.h>
     74 #endif
     75 #include <powerpc/kcore.h>
     76 #include <machine/powerpc.h>
     77 
     78 #ifdef MULTIPROCESSOR
     79 #include <powerpc/pic/ipivar.h>
     80 #include <machine/cpu_counter.h>
     81 #endif
     82 
     83 #ifdef DDB
     84 #include <machine/db_machdep.h>
     85 #include <ddb/db_output.h>
     86 #endif
     87 
     88 int cpu_timebase;
     89 int cpu_printfataltraps = 1;
     90 #if !defined(PPC_IBM4XX)
     91 extern int powersave;
     92 #endif
     93 
     94 /* exported variable to be filled in by the bootloaders */
     95 char *booted_kernel;
     96 
     97 const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
     98 	[PCU_FPU] = &fpu_ops,
     99 #if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
    100 	[PCU_VEC] = &vec_ops,
    101 #endif
    102 };
    103 
    104 #ifdef MULTIPROCESSOR
    105 struct cpuset_info cpuset_info;
    106 #endif
    107 
    108 /*
    109  * Set set up registers on exec.
    110  */
    111 void
    112 setregs(struct lwp *l, struct exec_package *epp, vaddr_t stack)
    113 {
    114 	struct proc * const p = l->l_proc;
    115 	struct trapframe * const tf = l->l_md.md_utf;
    116 	struct pcb * const pcb = lwp_getpcb(l);
    117 	struct ps_strings arginfo;
    118 	vaddr_t func = epp->ep_entry;
    119 
    120 	memset(tf, 0, sizeof *tf);
    121 	tf->tf_fixreg[1] = -roundup(-stack + 8, 16);
    122 
    123 	/*
    124 	 * XXX Machine-independent code has already copied arguments and
    125 	 * XXX environment to userland.  Get them back here.
    126 	 */
    127 	(void)copyin_psstrings(p, &arginfo);
    128 
    129 	/*
    130 	 * Set up arguments for _start():
    131 	 *	_start(argc, argv, envp, obj, cleanup, ps_strings);
    132 	 *
    133 	 * Notes:
    134 	 *	- obj and cleanup are the auxiliary and termination
    135 	 *	  vectors.  They are fixed up by ld.elf_so.
    136 	 *	- ps_strings is a NetBSD extension, and will be
    137 	 * 	  ignored by executables which are strictly
    138 	 *	  compliant with the SVR4 ABI.
    139 	 *
    140 	 * XXX We have to set both regs and retval here due to different
    141 	 * XXX calling convention in trap.c and init_main.c.
    142 	 */
    143 	tf->tf_fixreg[3] = arginfo.ps_nargvstr;
    144 	tf->tf_fixreg[4] = (register_t)arginfo.ps_argvstr;
    145 	tf->tf_fixreg[5] = (register_t)arginfo.ps_envstr;
    146 	tf->tf_fixreg[6] = 0;			/* auxiliary vector */
    147 	tf->tf_fixreg[7] = 0;			/* termination vector */
    148 	tf->tf_fixreg[8] = p->p_psstrp;		/* NetBSD extension */
    149 
    150 #ifdef _LP64
    151 	/*
    152 	 * For native ELF64, entry point to the function
    153 	 * descriptor which contains the real function address
    154 	 * and its TOC base address.
    155 	 */
    156 	uintptr_t fdesc[3] = { [0] = func, [1] = 0, [2] = 0 };
    157 	copyin((void *)func, fdesc, sizeof(fdesc));
    158 	tf->tf_fixreg[2] = fdesc[1] + epp->ep_entryoffset;
    159 	func = fdesc[0] + epp->ep_entryoffset;
    160 #endif
    161 	tf->tf_srr0 = func;
    162 	tf->tf_srr1 = PSL_MBO | PSL_USERSET;
    163 #ifdef ALTIVEC
    164 	tf->tf_vrsave = 0;
    165 #endif
    166 	pcb->pcb_flags = PSL_FE_DFLT;
    167 
    168 #if defined(PPC_BOOKE) || defined(PPC_IBM4XX)
    169 	p->p_md.md_ss_addr[0] = p->p_md.md_ss_addr[1] = 0;
    170 	p->p_md.md_ss_insn[0] = p->p_md.md_ss_insn[1] = 0;
    171 #endif
    172 }
    173 
    174 /*
    175  * Machine dependent system variables.
    176  */
    177 static int
    178 sysctl_machdep_cacheinfo(SYSCTLFN_ARGS)
    179 {
    180 	struct sysctlnode node = *rnode;
    181 
    182 	node.sysctl_data = &curcpu()->ci_ci;
    183 	node.sysctl_size = sizeof(curcpu()->ci_ci);
    184 	return (sysctl_lookup(SYSCTLFN_CALL(&node)));
    185 }
    186 
    187 #if !defined (PPC_IBM4XX)
    188 static int
    189 sysctl_machdep_powersave(SYSCTLFN_ARGS)
    190 {
    191 	struct sysctlnode node = *rnode;
    192 
    193 	if (powersave < 0)
    194 		node.sysctl_flags &= ~CTLFLAG_READWRITE;
    195 	return (sysctl_lookup(SYSCTLFN_CALL(&node)));
    196 }
    197 #endif
    198 
    199 static int
    200 sysctl_machdep_booted_device(SYSCTLFN_ARGS)
    201 {
    202 	struct sysctlnode node;
    203 
    204 	if (booted_device == NULL)
    205 		return (EOPNOTSUPP);
    206 
    207 	const char * const xname = device_xname(booted_device);
    208 
    209 	node = *rnode;
    210 	node.sysctl_data = __UNCONST(xname);
    211 	node.sysctl_size = strlen(xname) + 1;
    212 	return (sysctl_lookup(SYSCTLFN_CALL(&node)));
    213 }
    214 
    215 static int
    216 sysctl_machdep_booted_kernel(SYSCTLFN_ARGS)
    217 {
    218 	struct sysctlnode node;
    219 
    220 	if (booted_kernel == NULL || booted_kernel[0] == '\0')
    221 		return (EOPNOTSUPP);
    222 
    223 	node = *rnode;
    224 	node.sysctl_data = booted_kernel;
    225 	node.sysctl_size = strlen(booted_kernel) + 1;
    226 	return (sysctl_lookup(SYSCTLFN_CALL(&node)));
    227 }
    228 
    229 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
    230 {
    231 
    232 	sysctl_createv(clog, 0, NULL, NULL,
    233 		       CTLFLAG_PERMANENT,
    234 		       CTLTYPE_NODE, "machdep", NULL,
    235 		       NULL, 0, NULL, 0,
    236 		       CTL_MACHDEP, CTL_EOL);
    237 
    238 	/* Deprecated */
    239 	sysctl_createv(clog, 0, NULL, NULL,
    240 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    241 		       CTLTYPE_INT, "cachelinesize", NULL,
    242 		       NULL, curcpu()->ci_ci.dcache_line_size, NULL, 0,
    243 		       CTL_MACHDEP, CPU_CACHELINE, CTL_EOL);
    244 	sysctl_createv(clog, 0, NULL, NULL,
    245 		       CTLFLAG_PERMANENT,
    246 		       CTLTYPE_INT, "timebase", NULL,
    247 		       NULL, 0, &cpu_timebase, 0,
    248 		       CTL_MACHDEP, CPU_TIMEBASE, CTL_EOL);
    249 	sysctl_createv(clog, 0, NULL, NULL,
    250 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
    251 		       CTLTYPE_INT, "printfataltraps", NULL,
    252 		       NULL, 0, &cpu_printfataltraps, 0,
    253 		       CTL_MACHDEP, CPU_PRINTFATALTRAPS, CTL_EOL);
    254 	/* Use this instead of CPU_CACHELINE */
    255 	sysctl_createv(clog, 0, NULL, NULL,
    256 		       CTLFLAG_PERMANENT,
    257 		       CTLTYPE_STRUCT, "cacheinfo", NULL,
    258 		       sysctl_machdep_cacheinfo, 0, NULL, 0,
    259 		       CTL_MACHDEP, CPU_CACHEINFO, CTL_EOL);
    260 #if !defined (PPC_IBM4XX)
    261 	sysctl_createv(clog, 0, NULL, NULL,
    262 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
    263 		       CTLTYPE_INT, "powersave", NULL,
    264 		       sysctl_machdep_powersave, 0, &powersave, 0,
    265 		       CTL_MACHDEP, CPU_POWERSAVE, CTL_EOL);
    266 #endif
    267 #if defined(PPC_IBM4XX) || defined(PPC_BOOKE)
    268 	sysctl_createv(clog, 0, NULL, NULL,
    269 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    270 		       CTLTYPE_INT, "altivec", NULL,
    271 		       NULL, 0, NULL, 0,
    272 		       CTL_MACHDEP, CPU_ALTIVEC, CTL_EOL);
    273 #else
    274 	sysctl_createv(clog, 0, NULL, NULL,
    275 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    276 		       CTLTYPE_INT, "altivec", NULL,
    277 		       NULL, cpu_altivec, NULL, 0,
    278 		       CTL_MACHDEP, CPU_ALTIVEC, CTL_EOL);
    279 #endif
    280 #ifdef PPC_BOOKE
    281 	sysctl_createv(clog, 0, NULL, NULL,
    282 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    283 		       CTLTYPE_INT, "execprot", NULL,
    284 		       NULL, 1, NULL, 0,
    285 		       CTL_MACHDEP, CPU_EXECPROT, CTL_EOL);
    286 #endif
    287 	sysctl_createv(clog, 0, NULL, NULL,
    288 		       CTLFLAG_PERMANENT,
    289 		       CTLTYPE_STRING, "booted_device", NULL,
    290 		       sysctl_machdep_booted_device, 0, NULL, 0,
    291 		       CTL_MACHDEP, CPU_BOOTED_DEVICE, CTL_EOL);
    292 	sysctl_createv(clog, 0, NULL, NULL,
    293 		       CTLFLAG_PERMANENT,
    294 		       CTLTYPE_STRING, "booted_kernel", NULL,
    295 		       sysctl_machdep_booted_kernel, 0, NULL, 0,
    296 		       CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL);
    297 	sysctl_createv(clog, 0, NULL, NULL,
    298 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    299 		       CTLTYPE_INT, "fpu_present", NULL,
    300 		       NULL,
    301 #if defined(PPC_HAVE_FPU)
    302 		       1,
    303 #else
    304 		       0,
    305 #endif
    306 		       NULL, 0,
    307 		       CTL_MACHDEP, CPU_FPU, CTL_EOL);
    308 	sysctl_createv(clog, 0, NULL, NULL,
    309 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    310 		       CTLTYPE_INT, "no_unaligned", NULL,
    311 		       NULL,
    312 #if defined(PPC_NO_UNALIGNED)
    313 		       1,
    314 #else
    315 		       0,
    316 #endif
    317 		       NULL, 0,
    318 		       CTL_MACHDEP, CPU_NO_UNALIGNED, CTL_EOL);
    319 	sysctl_createv(clog, 0, NULL, NULL,
    320 		       CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    321 		       CTLTYPE_INT, "pvr", NULL,
    322 		       NULL,
    323 		       mfpvr(),
    324 		       NULL, 0,
    325 		       CTL_MACHDEP, CPU_PVR, CTL_EOL);
    326 }
    327 
    328 /*
    329  * Crash dump handling.
    330  */
    331 u_int32_t dumpmag = 0x8fca0101;		/* magic number */
    332 int dumpsize = 0;			/* size of dump in pages */
    333 long dumplo = -1;			/* blocks */
    334 
    335 /*
    336  * Calculate size of machine dependent kernel core dump headers.
    337  */
    338 int
    339 cpu_dumpsize(void)
    340 {
    341 	struct mem_region *mem, *avail;
    342 	unsigned nreg;
    343 	int size;
    344 
    345 	nreg = 0;
    346 	mem_regions(&mem, &avail);
    347 	while (mem->size != 0) {
    348 		nreg++;
    349 		mem++;
    350 	}
    351 
    352 	size = ALIGN(sizeof(kcore_seg_t)) +
    353 	       ALIGN(sizeof(cpu_kcore_hdr_t)) +
    354 	       ALIGN(nreg * sizeof(phys_ram_seg_t));
    355 	if (roundup(size, dbtob(1)) != dbtob(1)) {
    356 		return -1;
    357 	}
    358 
    359 	return 1;
    360 }
    361 
    362 /*
    363  * This is called by main to set dumplo and dumpsize.
    364  */
    365 void
    366 cpu_dumpconf(void)
    367 {
    368 	struct mem_region *mem, *avail;
    369 	u_long nblks, dumpblks;	/* size of dump area */
    370 
    371 	if (dumpdev == NODEV) {
    372 		return;
    373 	}
    374 
    375 	nblks = bdev_size(dumpdev);
    376 	if (nblks <= ctod(1)) {
    377 		return;
    378 	}
    379 
    380 	dumpsize = 0;
    381 	dumpblks = cpu_dumpsize();
    382 	if (dumpblks < 0) {
    383 		goto bad;
    384 	}
    385 
    386 	/* dumpsize is in page units, and doesn't include headers. */
    387 	mem_regions(&mem, &avail);
    388 	while (mem->size != 0) {
    389 		dumpsize += mem->size / PAGE_SIZE;
    390 		mem++;
    391 	}
    392 	dumpblks += ctod(dumpsize);
    393 
    394 	/* If dump won't fit (incl. room for possible label), punt. */
    395 	if (dumpblks > (nblks - ctod(1))) {
    396 		goto bad;
    397 	}
    398 
    399 	/* Put dump at end of partition. */
    400 	dumplo = nblks - dumpblks;
    401 
    402 	return;
    403 
    404 bad:
    405 	dumpsize = 0;
    406 }
    407 
    408 /*
    409  * Start a new LWP
    410  */
    411 void
    412 startlwp(void *arg)
    413 {
    414 	ucontext_t * const uc = arg;
    415 	lwp_t * const l = curlwp;
    416 	struct trapframe * const tf = l->l_md.md_utf;
    417 	int error __diagused;
    418 
    419 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
    420 	KASSERT(error == 0);
    421 
    422 	kmem_free(uc, sizeof(ucontext_t));
    423 	userret(l, tf);
    424 }
    425 
    426 /*
    427  * Process the tail end of a posix_spawn() for the child.
    428  */
    429 void
    430 cpu_spawn_return(struct lwp *l)
    431 {
    432 	struct trapframe * const tf = l->l_md.md_utf;
    433 
    434 	userret(l, tf);
    435 }
    436 
    437 bool
    438 cpu_intr_p(void)
    439 {
    440 
    441 	return curcpu()->ci_idepth >= 0;
    442 }
    443 
    444 void
    445 cpu_idle(void)
    446 {
    447 	KASSERT(mfmsr() & PSL_EE);
    448 	KASSERTMSG(curcpu()->ci_cpl == IPL_NONE,
    449 	    "ci_cpl = %d", curcpu()->ci_cpl);
    450 	(*curcpu()->ci_idlespin)();
    451 }
    452 
    453 void
    454 cpu_ast(struct lwp *l, struct cpu_info *ci)
    455 {
    456 	l->l_md.md_astpending = 0;	/* we are about to do it */
    457 	if (l->l_pflag & LP_OWEUPC) {
    458 		l->l_pflag &= ~LP_OWEUPC;
    459 		ADDUPROF(l);
    460 	}
    461 }
    462 
    463 void
    464 cpu_need_resched(struct cpu_info *ci, struct lwp *l, int flags)
    465 {
    466 	KASSERT(kpreempt_disabled());
    467 
    468 #ifdef __HAVE_PREEMPTION
    469 	if ((flags & RESCHED_KPREEMPT) != 0) {
    470 		if ((flags & RESCHED_REMOTE) != 0) {
    471 			cpu_send_ipi(cpu_index(ci), IPI_KPREEMPT);
    472 		} else {
    473 			softint_trigger(SOFTINT_KPREEMPT);
    474 		}
    475 		return;
    476 	}
    477 #endif
    478 	if ((flags & RESCHED_REMOTE) != 0) {
    479 #if defined(MULTIPROCESSOR)
    480 		cpu_send_ipi(cpu_index(ci), IPI_AST);
    481 #endif
    482 	} else {
    483 		l->l_md.md_astpending = 1;	/* force call to cpu_ast() */
    484 	}
    485 }
    486 
    487 void
    488 cpu_need_proftick(lwp_t *l)
    489 {
    490 	l->l_pflag |= LP_OWEUPC;
    491 	l->l_md.md_astpending = 1;
    492 }
    493 
    494 void
    495 cpu_signotify(lwp_t *l)
    496 {
    497 	if (l->l_cpu != curcpu()) {
    498 #if defined(MULTIPROCESSOR)
    499 		cpu_send_ipi(cpu_index(l->l_cpu), IPI_AST);
    500 #endif
    501 	} else {
    502 		l->l_md.md_astpending = 1;
    503 	}
    504 }
    505 
    506 vaddr_t
    507 cpu_lwp_pc(lwp_t *l)
    508 {
    509 	return l->l_md.md_utf->tf_srr0;
    510 }
    511 
    512 bool
    513 cpu_clkf_usermode(const struct clockframe *cf)
    514 {
    515 	return (cf->cf_srr1 & PSL_PR) != 0;
    516 }
    517 
    518 vaddr_t
    519 cpu_clkf_pc(const struct clockframe *cf)
    520 {
    521 	return cf->cf_srr0;
    522 }
    523 
    524 bool
    525 cpu_clkf_intr(const struct clockframe *cf)
    526 {
    527 	return cf->cf_idepth > 0;
    528 }
    529 
    530 #ifdef MULTIPROCESSOR
    531 /*
    532  * MD support for xcall(9) interface.
    533  */
    534 
    535 void
    536 xc_send_ipi(struct cpu_info *ci)
    537 {
    538 	KASSERT(kpreempt_disabled());
    539 	KASSERT(curcpu() != ci);
    540 
    541 	cpuid_t target = (ci != NULL ? cpu_index(ci) : IPI_DST_NOTME);
    542 
    543 	/* Unicast: remote CPU. */
    544 	/* Broadcast: all, but local CPU (caller will handle it). */
    545 	cpu_send_ipi(target, IPI_XCALL);
    546 }
    547 
    548 void
    549 cpu_ipi(struct cpu_info *ci)
    550 {
    551 	KASSERT(kpreempt_disabled());
    552 	KASSERT(curcpu() != ci);
    553 
    554 	cpuid_t target = (ci != NULL ? cpu_index(ci) : IPI_DST_NOTME);
    555 
    556 	/* Unicast: remote CPU. */
    557 	/* Broadcast: all, but local CPU (caller will handle it). */
    558 	cpu_send_ipi(target, IPI_GENERIC);
    559 }
    560 
    561 /* XXX kcpuset_create(9), kcpuset_clone(9) couldn't use interrupt context */
    562 typedef uint32_t __cpuset_t;
    563 CTASSERT(MAXCPUS <= 32);
    564 
    565 #define	CPUSET_SINGLE(cpu)		((__cpuset_t)1 << (cpu))
    566 
    567 #define	CPUSET_ADD(set, cpu)		atomic_or_32(&(set), CPUSET_SINGLE(cpu))
    568 #define	CPUSET_DEL(set, cpu)		atomic_and_32(&(set), ~CPUSET_SINGLE(cpu))
    569 #define	CPUSET_SUB(set1, set2)		atomic_and_32(&(set1), ~(set2))
    570 
    571 #define	CPUSET_EXCEPT(set, cpu)		((set) & ~CPUSET_SINGLE(cpu))
    572 
    573 #define	CPUSET_HAS_P(set, cpu)		((set) & CPUSET_SINGLE(cpu))
    574 #define	CPUSET_NEXT(set)		(ffs(set) - 1)
    575 
    576 #define	CPUSET_EMPTY_P(set)		((set) == (__cpuset_t)0)
    577 #define	CPUSET_EQUAL_P(set1, set2)	((set1) == (set2))
    578 #define	CPUSET_CLEAR(set)		((set) = (__cpuset_t)0)
    579 #define	CPUSET_ASSIGN(set1, set2)	((set1) = (set2))
    580 
    581 #define	CPUSET_EXPORT(kset, set)	kcpuset_export_u32((kset), &(set), sizeof(set))
    582 
    583 /*
    584  * Send an inter-processor interrupt to CPUs in cpuset (excludes curcpu())
    585  */
    586 static void
    587 cpu_multicast_ipi(__cpuset_t cpuset, uint32_t msg)
    588 {
    589 	CPU_INFO_ITERATOR cii;
    590 	struct cpu_info *ci;
    591 
    592 	CPUSET_DEL(cpuset, cpu_index(curcpu()));
    593 	if (CPUSET_EMPTY_P(cpuset))
    594 		return;
    595 
    596 	for (CPU_INFO_FOREACH(cii, ci)) {
    597 		const int index = cpu_index(ci);
    598 		if (CPUSET_HAS_P(cpuset, index)) {
    599 			CPUSET_DEL(cpuset, index);
    600 			cpu_send_ipi(index, msg);
    601 		}
    602 	}
    603 }
    604 
    605 static void
    606 cpu_ipi_error(const char *s, kcpuset_t *succeeded, __cpuset_t expected)
    607 {
    608 	__cpuset_t cpuset;
    609 
    610 	CPUSET_EXPORT(succeeded, cpuset);
    611 	CPUSET_SUB(expected, cpuset);
    612 	if (!CPUSET_EMPTY_P(expected)) {
    613 		printf("Failed to %s:", s);
    614 		do {
    615 			const int index = CPUSET_NEXT(expected);
    616 			CPUSET_DEL(expected, index);
    617 			printf(" cpu%d", index);
    618 		} while (!CPUSET_EMPTY_P(expected));
    619 		printf("\n");
    620 	}
    621 }
    622 
    623 static int
    624 cpu_ipi_wait(kcpuset_t *watchset, __cpuset_t mask)
    625 {
    626 	uint64_t tmout = curcpu()->ci_data.cpu_cc_freq; /* some finite amount of time */
    627 	__cpuset_t cpuset;
    628 
    629 	while (tmout--) {
    630 		CPUSET_EXPORT(watchset, cpuset);
    631 		if (cpuset == mask)
    632 			return 0;		/* success */
    633 	}
    634 	return 1;				/* timed out */
    635 }
    636 
    637 /*
    638  * Halt this cpu.
    639  */
    640 void
    641 cpu_halt(void)
    642 {
    643 	struct cpuset_info * const csi = &cpuset_info;
    644 	const cpuid_t index = cpu_index(curcpu());
    645 
    646 	printf("cpu%ld: shutting down\n", index);
    647 	kcpuset_set(csi->cpus_halted, index);
    648 	spl0();			/* allow interrupts e.g. further ipi ? */
    649 
    650 	/* spin */
    651 	for (;;)
    652 		continue;
    653 	/*NOTREACHED*/
    654 }
    655 
    656 /*
    657  * Halt all running cpus, excluding current cpu.
    658  */
    659 void
    660 cpu_halt_others(void)
    661 {
    662 	struct cpuset_info * const csi = &cpuset_info;
    663 	const cpuid_t index = cpu_index(curcpu());
    664 	__cpuset_t cpumask, cpuset, halted;
    665 
    666 	KASSERT(kpreempt_disabled());
    667 
    668 	CPUSET_EXPORT(csi->cpus_running, cpuset);
    669 	CPUSET_DEL(cpuset, index);
    670 	CPUSET_ASSIGN(cpumask, cpuset);
    671 	CPUSET_EXPORT(csi->cpus_halted, halted);
    672 	CPUSET_SUB(cpuset, halted);
    673 
    674 	if (CPUSET_EMPTY_P(cpuset))
    675 		return;
    676 
    677 	cpu_multicast_ipi(cpuset, IPI_HALT);
    678 	if (cpu_ipi_wait(csi->cpus_halted, cpumask))
    679 		cpu_ipi_error("halt", csi->cpus_halted, cpumask);
    680 
    681 	/*
    682 	 * TBD
    683 	 * Depending on available firmware methods, other cpus will
    684 	 * either shut down themselves, or spin and wait for us to
    685 	 * stop them.
    686 	 */
    687 }
    688 
    689 /*
    690  * Pause this cpu.
    691  */
    692 void
    693 cpu_pause(struct trapframe *tf)
    694 {
    695 	volatile struct cpuset_info * const csi = &cpuset_info;
    696 	int s = splhigh();
    697 	const cpuid_t index = cpu_index(curcpu());
    698 
    699 	for (;;) {
    700 		kcpuset_set(csi->cpus_paused, index);
    701 		while (kcpuset_isset(csi->cpus_paused, index))
    702 			docritpollhooks();
    703 		kcpuset_set(csi->cpus_resumed, index);
    704 #ifdef DDB
    705 		if (ddb_running_on_this_cpu_p())
    706 			cpu_Debugger();
    707 		if (ddb_running_on_any_cpu_p())
    708 			continue;
    709 #endif	/* DDB */
    710 		break;
    711 	}
    712 
    713 	splx(s);
    714 }
    715 
    716 /*
    717  * Pause all running cpus, excluding current cpu.
    718  */
    719 void
    720 cpu_pause_others(void)
    721 {
    722 	struct cpuset_info * const csi = &cpuset_info;
    723 	const cpuid_t index = cpu_index(curcpu());
    724 	__cpuset_t cpuset;
    725 
    726 	KASSERT(kpreempt_disabled());
    727 
    728 	CPUSET_EXPORT(csi->cpus_running, cpuset);
    729 	CPUSET_DEL(cpuset, index);
    730 
    731 	if (CPUSET_EMPTY_P(cpuset))
    732 		return;
    733 
    734 	cpu_multicast_ipi(cpuset, IPI_SUSPEND);
    735 	if (cpu_ipi_wait(csi->cpus_paused, cpuset))
    736 		cpu_ipi_error("pause", csi->cpus_paused, cpuset);
    737 }
    738 
    739 /*
    740  * Resume a single cpu.
    741  */
    742 void
    743 cpu_resume(cpuid_t index)
    744 {
    745 	struct cpuset_info * const csi = &cpuset_info;
    746 	__cpuset_t cpuset = CPUSET_SINGLE(index);
    747 
    748 	kcpuset_zero(csi->cpus_resumed);
    749 	kcpuset_clear(csi->cpus_paused, index);
    750 
    751 	if (cpu_ipi_wait(csi->cpus_paused, cpuset))
    752 		cpu_ipi_error("resume", csi->cpus_resumed, cpuset);
    753 }
    754 
    755 /*
    756  * Resume all paused cpus.
    757  */
    758 void
    759 cpu_resume_others(void)
    760 {
    761 	struct cpuset_info * const csi = &cpuset_info;
    762 	__cpuset_t cpuset;
    763 
    764 	kcpuset_zero(csi->cpus_resumed);
    765 	CPUSET_EXPORT(csi->cpus_paused, cpuset);
    766 	kcpuset_zero(csi->cpus_paused);
    767 
    768 	if (cpu_ipi_wait(csi->cpus_resumed, cpuset))
    769 		cpu_ipi_error("resume", csi->cpus_resumed, cpuset);
    770 }
    771 
    772 int
    773 cpu_is_paused(int index)
    774 {
    775 	struct cpuset_info * const csi = &cpuset_info;
    776 
    777 	return kcpuset_isset(csi->cpus_paused, index);
    778 }
    779 
    780 #ifdef DDB
    781 void
    782 cpu_debug_dump(void)
    783 {
    784 	struct cpuset_info * const csi = &cpuset_info;
    785 	CPU_INFO_ITERATOR cii;
    786 	struct cpu_info *ci;
    787 	char running, hatched, paused, resumed, halted;
    788 
    789 #ifdef _LP64
    790 	db_printf("CPU CPUID STATE CPUINFO          CPL INT MTX IPIS\n");
    791 #else
    792 	db_printf("CPU CPUID STATE CPUINFO  CPL INT MTX IPIS\n");
    793 #endif
    794 	for (CPU_INFO_FOREACH(cii, ci)) {
    795 		const cpuid_t index = cpu_index(ci);
    796 		hatched = (kcpuset_isset(csi->cpus_hatched, index) ? 'H' : '-');
    797 		running = (kcpuset_isset(csi->cpus_running, index) ? 'R' : '-');
    798 		paused  = (kcpuset_isset(csi->cpus_paused,  index) ? 'P' : '-');
    799 		resumed = (kcpuset_isset(csi->cpus_resumed, index) ? 'r' : '-');
    800 		halted  = (kcpuset_isset(csi->cpus_halted,  index) ? 'h' : '-');
    801 		db_printf("%3ld 0x%03x %c%c%c%c%c %p %3d %3d %3d 0x%08x\n",
    802 		    index, ci->ci_cpuid,
    803 		    running, hatched, paused, resumed, halted,
    804 		    ci, ci->ci_cpl, ci->ci_idepth, ci->ci_mtx_count,
    805 		    ci->ci_pending_ipis);
    806 	}
    807 }
    808 #endif	/* DDB */
    809 #endif /* MULTIPROCESSOR */
    810 
    811 int
    812 emulate_mxmsr(struct lwp *l, struct trapframe *tf, uint32_t opcode)
    813 {
    814 
    815 #define	OPC_MFMSR_CODE		0x7c0000a6
    816 #define	OPC_MFMSR_MASK		0xfc1fffff
    817 #define	OPC_MFMSR_P(o)		(((o) & OPC_MFMSR_MASK) == OPC_MFMSR_CODE)
    818 
    819 #define	OPC_MTMSR_CODE		0x7c000124
    820 #define	OPC_MTMSR_MASK		0xfc1fffff
    821 #define	OPC_MTMSR_P(o)		(((o) & OPC_MTMSR_MASK) == OPC_MTMSR_CODE)
    822 
    823 #define	OPC_MXMSR_REG(o)	(((o) >> 21) & 0x1f)
    824 
    825 	if (OPC_MFMSR_P(opcode)) {
    826 		struct pcb * const pcb = lwp_getpcb(l);
    827 		register_t msr = tf->tf_srr1 & PSL_USERSRR1;
    828 
    829 		if (fpu_used_p(l))
    830 			msr |= PSL_FP;
    831 #ifdef ALTIVEC
    832 		if (vec_used_p(l))
    833 			msr |= PSL_VEC;
    834 #endif
    835 
    836 		msr |= (pcb->pcb_flags & PSL_FE_PREC);
    837 		tf->tf_fixreg[OPC_MXMSR_REG(opcode)] = msr;
    838 		return 1;
    839 	}
    840 
    841 	if (OPC_MTMSR_P(opcode)) {
    842 		struct pcb * const pcb = lwp_getpcb(l);
    843 		register_t msr = tf->tf_fixreg[OPC_MXMSR_REG(opcode)];
    844 
    845 		/*
    846 		 * Ignore the FP enable bit in the requested MSR.
    847 		 * It might be set in the thread's actual MSR but the
    848 		 * user code isn't allowed to change it.
    849 		 */
    850 		msr &= ~PSL_FP;
    851 #ifdef ALTIVEC
    852 		msr &= ~PSL_VEC;
    853 #endif
    854 
    855 		/*
    856 		 * Don't let the user muck with bits he's not allowed to.
    857 		 */
    858 #ifdef PPC_HAVE_FPU
    859 		if (!PSL_USEROK_P(msr))
    860 #else
    861 		if (!PSL_USEROK_P(msr & ~PSL_FE_PREC))
    862 #endif
    863 			return 0;
    864 
    865 		/*
    866 		 * For now, only update the FP exception mode.
    867 		 */
    868 		pcb->pcb_flags &= ~PSL_FE_PREC;
    869 		pcb->pcb_flags |= msr & PSL_FE_PREC;
    870 
    871 #ifdef PPC_HAVE_FPU
    872 		/*
    873 		 * If we think we have the FPU, update SRR1 too.  If we're
    874 		 * wrong userret() will take care of it.
    875 		 */
    876 		if (tf->tf_srr1 & PSL_FP) {
    877 			tf->tf_srr1 &= ~(PSL_FE0|PSL_FE1);
    878 			tf->tf_srr1 |= msr & (PSL_FE0|PSL_FE1);
    879 		}
    880 #endif
    881 		return 1;
    882 	}
    883 
    884 	return 0;
    885 }
    886 
    887 bool
    888 mm_md_direct_mapped_phys(paddr_t pa, vaddr_t *vap)
    889 {
    890 	if (atop(pa) < physmem) {
    891 		*vap = pa;
    892 		return true;
    893 	}
    894 
    895 	return false;
    896 }
    897 
    898 int
    899 mm_md_physacc(paddr_t pa, vm_prot_t prot)
    900 {
    901 
    902 	return (atop(pa) < physmem) ? 0 : EFAULT;
    903 }
    904 
    905 int
    906 mm_md_kernacc(void *va, vm_prot_t prot, bool *handled)
    907 {
    908 	if (atop((paddr_t)va) < physmem) {
    909 		*handled = true;
    910 		return 0;
    911 	}
    912 
    913 	if ((vaddr_t)va < VM_MIN_KERNEL_ADDRESS
    914 	    || (vaddr_t)va >= VM_MAX_KERNEL_ADDRESS)
    915 		return EFAULT;
    916 
    917 	*handled = false;
    918 	return 0;
    919 }
    920