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 85 int cpu_timebase; 86 int cpu_printfataltraps = 1; 87 #if !defined(PPC_IBM4XX) 88 extern int powersave; 89 #endif 90 91 /* exported variable to be filled in by the bootloaders */ 92 char *booted_kernel; 93 94 const 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 102 struct cpuset_info cpuset_info; 103 #endif 104 105 /* 106 * Set set up registers on exec. 107 */ 108 void 109 setregs(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 */ 174 static int 175 sysctl_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) 185 static int 186 sysctl_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 196 static int 197 sysctl_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 212 static int 213 sysctl_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 226 SYSCTL_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 */ 321 u_int32_t dumpmag = 0x8fca0101; /* magic number */ 322 int dumpsize = 0; /* size of dump in pages */ 323 long dumplo = -1; /* blocks */ 324 325 /* 326 * This is called by main to set dumplo and dumpsize. 327 */ 328 void 329 cpu_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 */ 359 void 360 startlwp(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 */ 377 void 378 cpu_spawn_return(struct lwp *l) 379 { 380 struct trapframe * const tf = l->l_md.md_utf; 381 382 userret(l, tf); 383 } 384 385 bool 386 cpu_intr_p(void) 387 { 388 389 return curcpu()->ci_idepth >= 0; 390 } 391 392 void 393 cpu_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 401 void 402 cpu_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 411 void 412 cpu_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 435 void 436 cpu_need_proftick(lwp_t *l) 437 { 438 l->l_pflag |= LP_OWEUPC; 439 l->l_md.md_astpending = 1; 440 } 441 442 void 443 cpu_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 454 vaddr_t 455 cpu_lwp_pc(lwp_t *l) 456 { 457 return l->l_md.md_utf->tf_srr0; 458 } 459 460 bool 461 cpu_clkf_usermode(const struct clockframe *cf) 462 { 463 return (cf->cf_srr1 & PSL_PR) != 0; 464 } 465 466 vaddr_t 467 cpu_clkf_pc(const struct clockframe *cf) 468 { 469 return cf->cf_srr0; 470 } 471 472 bool 473 cpu_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 483 void 484 xc_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 496 void 497 cpu_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 */ 510 typedef uint32_t __cpuset_t; 511 CTASSERT(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 */ 534 static void 535 cpu_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 553 static void 554 cpu_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 571 static int 572 cpu_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 */ 588 void 589 cpu_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 */ 607 void 608 cpu_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 */ 640 void 641 cpu_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 */ 667 void 668 cpu_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 */ 690 void 691 cpu_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 */ 706 void 707 cpu_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 720 int 721 cpu_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 729 void 730 cpu_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 759 int 760 emulate_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 */ 839 void 840 module_init_md(void) 841 { 842 } 843 #endif 844 845 bool 846 mm_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 856 int 857 mm_md_physacc(paddr_t pa, vm_prot_t prot) 858 { 859 860 return (atop(pa) < physmem) ? 0 : EFAULT; 861 } 862 863 int 864 mm_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