9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * Process switching routines.
27 */
28
29 #if !defined(lint)
30 #include "assym.h"
31 #else /* lint */
32 #include <sys/thread.h>
33 #endif /* lint */
34
35 #include <sys/param.h>
36 #include <sys/asm_linkage.h>
37 #include <sys/mmu.h>
38 #include <sys/pcb.h>
39 #include <sys/machthread.h>
40 #include <sys/machclock.h>
41 #include <sys/privregs.h>
42 #include <sys/vtrace.h>
43 #include <vm/hat_sfmmu.h>
44
45 /*
46 * resume(kthread_id_t)
47 *
48 * a thread can only run on one processor at a time. there
49 * exists a window on MPs where the current thread on one
50 * processor is capable of being dispatched by another processor.
51 * some overlap between outgoing and incoming threads can happen
52 * when they are the same thread. in this case where the threads
53 * are the same, resume() on one processor will spin on the incoming
54 * thread until resume() on the other processor has finished with
55 * the outgoing thread.
56 *
57 * The MMU context changes when the resuming thread resides in a different
58 * process. Kernel threads are known by resume to reside in process 0.
59 * The MMU context, therefore, only changes when resuming a thread in
60 * a process different from curproc.
61 *
62 * resume_from_intr() is called when the thread being resumed was not
63 * passivated by resume (e.g. was interrupted). This means that the
64 * resume lock is already held and that a restore context is not needed.
65 * Also, the MMU context is not changed on the resume in this case.
66 *
67 * resume_from_zombie() is the same as resume except the calling thread
68 * is a zombie and must be put on the deathrow list after the CPU is
69 * off the stack.
70 */
71
72 #if defined(lint)
73
74 /* ARGSUSED */
75 void
76 resume(kthread_id_t t)
77 {}
78
79 #else /* lint */
80
81 ENTRY(resume)
82 save %sp, -SA(MINFRAME), %sp ! save ins and locals
83
84 call __dtrace_probe___sched_off__cpu ! DTrace probe
85 mov %i0, %o0 ! arg for DTrace probe
86
87 membar #Sync ! flush writebuffers
88 flushw ! flushes all but this window
89
90 stn %i7, [THREAD_REG + T_PC] ! save return address
91 stn %fp, [THREAD_REG + T_SP] ! save sp
92
93 !
94 ! Save GSR (Graphics Status Register).
95 !
96 ! Read fprs, call fp_save if FPRS_FEF set.
97 ! This handles floating-point state saving.
98 ! The fprs could be turned on by hw bcopy software,
99 ! *or* by fp_disabled. Handle it either way.
100 !
437 casx [%o2], %o1, %o0
438 cmp %o0, %o1
439 be,pt %xcc, 5b
440 nop
441 ! If an interrupt occurred while we were attempting to store
442 ! the timestamp, try again.
443 ba,pt %xcc, 1b
444 nop
445
446 !
447 ! lock failed - spin with regular load to avoid cache-thrashing.
448 !
449 7:
450 brnz,a,pt %o0, 7b ! spin while locked
451 ldub [%i0 + T_LOCK], %o0
452 ba %xcc, 6b
453 ldstub [%i0 + T_LOCK], %o0 ! delay - lock curthread's mutex
454 SET_SIZE(_resume_from_idle)
455 SET_SIZE(resume)
456
457 #endif /* lint */
458
459 #if defined(lint)
460
461 /* ARGSUSED */
462 void
463 resume_from_zombie(kthread_id_t t)
464 {}
465
466 #else /* lint */
467
468 ENTRY(resume_from_zombie)
469 save %sp, -SA(MINFRAME), %sp ! save ins and locals
470
471 call __dtrace_probe___sched_off__cpu ! DTrace probe
472 mov %i0, %o0 ! arg for DTrace probe
473
474 ldn [THREAD_REG + T_CPU], %i1 ! cpu pointer
475
476 flushw ! flushes all but this window
477 ldn [THREAD_REG + T_PROCP], %i2 ! old procp for mmu ctx
478
479 !
480 ! Temporarily switch to the idle thread's stack so that
481 ! the zombie thread's stack can be reclaimed by the reaper.
482 !
483 ldn [%i1 + CPU_IDLE_THREAD], %o2 ! idle thread pointer
484 ldn [%o2 + T_SP], %o1 ! get onto idle thread stack
485 sub %o1, SA(MINFRAME), %sp ! save room for ins and locals
486 clr %fp
487 !
492 mov %o2, THREAD_REG ! set %g7 to idle
493 stn %g0, [%i1 + CPU_MPCB] ! clear mpcb
494 #ifdef CPU_MPCB_PA
495 mov -1, %o1
496 stx %o1, [%i1 + CPU_MPCB_PA]
497 #endif
498 call reapq_add ! reapq_add(old_thread);
499 stn %o2, [%i1 + CPU_THREAD] ! delay - CPU's thread = idle
500
501 !
502 ! resume_from_idle args:
503 ! %i0 = new thread
504 ! %i1 = cpu
505 ! %i2 = old proc
506 ! %i3 = new proc
507 !
508 b _resume_from_idle ! finish job of resume
509 ldn [%i0 + T_PROCP], %i3 ! new process
510 SET_SIZE(resume_from_zombie)
511
512 #endif /* lint */
513
514 #if defined(lint)
515
516 /* ARGSUSED */
517 void
518 resume_from_intr(kthread_id_t t)
519 {}
520
521 #else /* lint */
522
523 ENTRY(resume_from_intr)
524 save %sp, -SA(MINFRAME), %sp ! save ins and locals
525
526 !
527 ! We read in the fprs and call fp_save if FPRS_FEF is set
528 ! to save the floating-point state if fprs has been
529 ! modified by operations such as hw bcopy or fp_disabled.
530 ! This is to resolve an issue where an interrupting thread
531 ! doesn't retain their floating-point registers when
532 ! switching out of the interrupt context.
533 !
534 rd %fprs, %g4
535 ldn [THREAD_REG + T_STACK], %i2
536 andcc %g4, FPRS_FEF, %g0 ! is FPRS_FEF set
537 bz,pt %icc, 4f
538 st %g4, [%i2 + SA(MINFRAME) + FPU_FPRS] ! save fprs
539
540 ! save kernel fp state in stack
541 add %i2, SA(MINFRAME), %o0 ! %o0 = kfpu_t ptr
542 rd %gsr, %g5
597 casx [%o2], %o1, %o0
598 cmp %o0, %o1
599 bne,pn %xcc, 2b
600 ldn [THREAD_REG + T_INTR], %l1 ! delay
601 ! Reset cpu_intrcnt if we aren't pinning anyone
602 brz,a,pt %l1, 2f
603 stub %g0, [%i1 + CPU_INTRCNT]
604 2:
605 ba,pt %xcc, 1b
606 nop
607 3:
608 !
609 ! We're a non-interrupt thread and cpu_kprunrun is set. call kpreempt.
610 !
611 call kpreempt
612 mov KPREEMPT_SYNC, %o0
613 ba,pt %xcc, 1b
614 nop
615 SET_SIZE(resume_from_intr)
616
617 #endif /* lint */
618
619
620 /*
621 * thread_start()
622 *
623 * the current register window was crafted by thread_run() to contain
624 * an address of a procedure (in register %i7), and its args in registers
625 * %i0 through %i5. a stack trace of this thread will show the procedure
626 * that thread_start() invoked at the bottom of the stack. an exit routine
627 * is stored in %l0 and called when started thread returns from its called
628 * procedure.
629 */
630
631 #if defined(lint)
632
633 void
634 thread_start(void)
635 {}
636
637 #else /* lint */
638
639 ENTRY(thread_start)
640 mov %i0, %o0
641 jmpl %i7, %o7 ! call thread_run()'s start() procedure.
642 mov %i1, %o1
643
644 call thread_exit ! destroy thread if it returns.
645 nop
646 unimp 0
647 SET_SIZE(thread_start)
648
649 #endif /* lint */
|
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * Process switching routines.
27 */
28
29 #include "assym.h"
30
31 #include <sys/param.h>
32 #include <sys/asm_linkage.h>
33 #include <sys/mmu.h>
34 #include <sys/pcb.h>
35 #include <sys/machthread.h>
36 #include <sys/machclock.h>
37 #include <sys/privregs.h>
38 #include <sys/vtrace.h>
39 #include <vm/hat_sfmmu.h>
40
41 /*
42 * resume(kthread_id_t)
43 *
44 * a thread can only run on one processor at a time. there
45 * exists a window on MPs where the current thread on one
46 * processor is capable of being dispatched by another processor.
47 * some overlap between outgoing and incoming threads can happen
48 * when they are the same thread. in this case where the threads
49 * are the same, resume() on one processor will spin on the incoming
50 * thread until resume() on the other processor has finished with
51 * the outgoing thread.
52 *
53 * The MMU context changes when the resuming thread resides in a different
54 * process. Kernel threads are known by resume to reside in process 0.
55 * The MMU context, therefore, only changes when resuming a thread in
56 * a process different from curproc.
57 *
58 * resume_from_intr() is called when the thread being resumed was not
59 * passivated by resume (e.g. was interrupted). This means that the
60 * resume lock is already held and that a restore context is not needed.
61 * Also, the MMU context is not changed on the resume in this case.
62 *
63 * resume_from_zombie() is the same as resume except the calling thread
64 * is a zombie and must be put on the deathrow list after the CPU is
65 * off the stack.
66 */
67
68 ENTRY(resume)
69 save %sp, -SA(MINFRAME), %sp ! save ins and locals
70
71 call __dtrace_probe___sched_off__cpu ! DTrace probe
72 mov %i0, %o0 ! arg for DTrace probe
73
74 membar #Sync ! flush writebuffers
75 flushw ! flushes all but this window
76
77 stn %i7, [THREAD_REG + T_PC] ! save return address
78 stn %fp, [THREAD_REG + T_SP] ! save sp
79
80 !
81 ! Save GSR (Graphics Status Register).
82 !
83 ! Read fprs, call fp_save if FPRS_FEF set.
84 ! This handles floating-point state saving.
85 ! The fprs could be turned on by hw bcopy software,
86 ! *or* by fp_disabled. Handle it either way.
87 !
424 casx [%o2], %o1, %o0
425 cmp %o0, %o1
426 be,pt %xcc, 5b
427 nop
428 ! If an interrupt occurred while we were attempting to store
429 ! the timestamp, try again.
430 ba,pt %xcc, 1b
431 nop
432
433 !
434 ! lock failed - spin with regular load to avoid cache-thrashing.
435 !
436 7:
437 brnz,a,pt %o0, 7b ! spin while locked
438 ldub [%i0 + T_LOCK], %o0
439 ba %xcc, 6b
440 ldstub [%i0 + T_LOCK], %o0 ! delay - lock curthread's mutex
441 SET_SIZE(_resume_from_idle)
442 SET_SIZE(resume)
443
444 ENTRY(resume_from_zombie)
445 save %sp, -SA(MINFRAME), %sp ! save ins and locals
446
447 call __dtrace_probe___sched_off__cpu ! DTrace probe
448 mov %i0, %o0 ! arg for DTrace probe
449
450 ldn [THREAD_REG + T_CPU], %i1 ! cpu pointer
451
452 flushw ! flushes all but this window
453 ldn [THREAD_REG + T_PROCP], %i2 ! old procp for mmu ctx
454
455 !
456 ! Temporarily switch to the idle thread's stack so that
457 ! the zombie thread's stack can be reclaimed by the reaper.
458 !
459 ldn [%i1 + CPU_IDLE_THREAD], %o2 ! idle thread pointer
460 ldn [%o2 + T_SP], %o1 ! get onto idle thread stack
461 sub %o1, SA(MINFRAME), %sp ! save room for ins and locals
462 clr %fp
463 !
468 mov %o2, THREAD_REG ! set %g7 to idle
469 stn %g0, [%i1 + CPU_MPCB] ! clear mpcb
470 #ifdef CPU_MPCB_PA
471 mov -1, %o1
472 stx %o1, [%i1 + CPU_MPCB_PA]
473 #endif
474 call reapq_add ! reapq_add(old_thread);
475 stn %o2, [%i1 + CPU_THREAD] ! delay - CPU's thread = idle
476
477 !
478 ! resume_from_idle args:
479 ! %i0 = new thread
480 ! %i1 = cpu
481 ! %i2 = old proc
482 ! %i3 = new proc
483 !
484 b _resume_from_idle ! finish job of resume
485 ldn [%i0 + T_PROCP], %i3 ! new process
486 SET_SIZE(resume_from_zombie)
487
488 ENTRY(resume_from_intr)
489 save %sp, -SA(MINFRAME), %sp ! save ins and locals
490
491 !
492 ! We read in the fprs and call fp_save if FPRS_FEF is set
493 ! to save the floating-point state if fprs has been
494 ! modified by operations such as hw bcopy or fp_disabled.
495 ! This is to resolve an issue where an interrupting thread
496 ! doesn't retain their floating-point registers when
497 ! switching out of the interrupt context.
498 !
499 rd %fprs, %g4
500 ldn [THREAD_REG + T_STACK], %i2
501 andcc %g4, FPRS_FEF, %g0 ! is FPRS_FEF set
502 bz,pt %icc, 4f
503 st %g4, [%i2 + SA(MINFRAME) + FPU_FPRS] ! save fprs
504
505 ! save kernel fp state in stack
506 add %i2, SA(MINFRAME), %o0 ! %o0 = kfpu_t ptr
507 rd %gsr, %g5
562 casx [%o2], %o1, %o0
563 cmp %o0, %o1
564 bne,pn %xcc, 2b
565 ldn [THREAD_REG + T_INTR], %l1 ! delay
566 ! Reset cpu_intrcnt if we aren't pinning anyone
567 brz,a,pt %l1, 2f
568 stub %g0, [%i1 + CPU_INTRCNT]
569 2:
570 ba,pt %xcc, 1b
571 nop
572 3:
573 !
574 ! We're a non-interrupt thread and cpu_kprunrun is set. call kpreempt.
575 !
576 call kpreempt
577 mov KPREEMPT_SYNC, %o0
578 ba,pt %xcc, 1b
579 nop
580 SET_SIZE(resume_from_intr)
581
582
583 /*
584 * thread_start()
585 *
586 * the current register window was crafted by thread_run() to contain
587 * an address of a procedure (in register %i7), and its args in registers
588 * %i0 through %i5. a stack trace of this thread will show the procedure
589 * that thread_start() invoked at the bottom of the stack. an exit routine
590 * is stored in %l0 and called when started thread returns from its called
591 * procedure.
592 */
593
594 ENTRY(thread_start)
595 mov %i0, %o0
596 jmpl %i7, %o7 ! call thread_run()'s start() procedure.
597 mov %i1, %o1
598
599 call thread_exit ! destroy thread if it returns.
600 nop
601 unimp 0
602 SET_SIZE(thread_start)
|