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