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