4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * System call trap handler.
29 #include <sys/asm_linkage.h>
30 #include <sys/machpcb.h>
31 #include <sys/machthread.h>
32 #include <sys/syscall.h>
34 #include <sys/machtrap.h>
36 #include <sys/machparam.h>
41 #include <sys/traptrace.h>
42 #endif /* TRAPTRACE */
45 #if (1 << SYSENT_SHIFT) != SYSENT_SIZE
46 #error "SYSENT_SHIFT does not correspond to size of sysent structure"
50 * Native System call trap handler.
52 * We branch here from sys_trap when a 64-bit system call occurs.
58 * %l0 = saved return address
62 ENTRY_NP
(syscall_trap
)
63 ldn
[THREAD_REG
+ T_CPU
], %g1
! get cpu pointer
64 mov
%o7
, %l0
! save return addr
66 ! If the trapping thread has the address mask bit set
, then it
's
67 ! a 32-bit process, and has no business calling 64-bit syscalls.
69 ldx [%o0 + TSTATE_OFF], %l1 ! saved %tstate.am is that
70 andcc %l1, TSTATE_AM, %l1 ! of the trapping proc
71 bne,pn %xcc, _syscall_ill !
72 mov %o0, %l1 ! save reg pointer
73 mov %i0, %o0 ! copy 1st arg
74 mov %i1, %o1 ! copy 2nd arg
75 ldx [%g1 + CPU_STATS_SYS_SYSCALL], %g2
76 inc %g2 ! cpu_stats.sys.syscall++
77 stx %g2, [%g1 + CPU_STATS_SYS_SYSCALL]
80 ! Set new state for LWP
82 ldn [THREAD_REG + T_LWP], %l2
84 mov %i2, %o2 ! copy 3rd arg
85 stb %g3, [%l2 + LWP_STATE]
86 mov %i3, %o3 ! copy 4th arg
87 ldx [%l2 + LWP_RU_SYSC], %g2 ! pesky statistics
88 mov %i4, %o4 ! copy 5th arg
90 stx %g2, [%l2 + LWP_RU_SYSC]
91 mov %i5, %o5 ! copy 6th arg
92 ! args for direct syscalls now set up
96 ! make trap trace entry - helps in debugging
99 andn %l3, PSTATE_IE | PSTATE_AM, %g3
100 wrpr %g0, %g3, %pstate ! disable interrupt
101 TRACE_PTR(%g3, %g2) ! get trace pointer
102 GET_TRACE_TICK(%g1, %g2)
103 stxa %g1, [%g3 + TRAP_ENT_TICK]%asi
104 ldx [%l1 + G1_OFF], %g1 ! get syscall code
105 TRACE_SAVE_TL_VAL(%g3, %g1)
106 TRACE_SAVE_GL_VAL(%g3, %g0)
108 stha %g2, [%g3 + TRAP_ENT_TT]%asi
109 stxa %g7, [%g3 + TRAP_ENT_TSTATE]%asi ! save thread in tstate space
110 stna %sp, [%g3 + TRAP_ENT_SP]%asi
111 stna %o0, [%g3 + TRAP_ENT_F1]%asi
112 stna %o1, [%g3 + TRAP_ENT_F2]%asi
113 stna %o2, [%g3 + TRAP_ENT_F3]%asi
114 stna %o3, [%g3 + TRAP_ENT_F4]%asi
115 stna %o4, [%g3 + TRAP_ENT_TPC]%asi
116 stna %o5, [%g3 + TRAP_ENT_TR]%asi
117 TRACE_NEXT(%g3, %g2, %g1) ! set new trace pointer
118 wrpr %g0, %l3, %pstate ! enable interrupt
119 #endif /* TRAPTRACE */
122 ! Test for pre-system-call handling
124 ldub [THREAD_REG + T_PRE_SYS], %g3 ! pre-syscall proc?
126 sethi %hi(syscalltrace), %g4
127 ld [%g4 + %lo(syscalltrace)], %g4
128 orcc %g3, %g4, %g0 ! pre_syscall OR syscalltrace?
130 tst %g3 ! is pre_syscall flag set?
131 #endif /* SYSCALLTRACE */
133 bnz,pn %icc, _syscall_pre
136 ! Fast path invocation of new_mstate
142 ldx [%l1 + O0_OFF], %o0 ! restore %o0
143 ldx [%l1 + O1_OFF], %o1 ! restore %o1
144 ldx [%l1 + O2_OFF], %o2
145 ldx [%l1 + O3_OFF], %o3
146 ldx [%l1 + O4_OFF], %o4
147 ldx [%l1 + O5_OFF], %o5
152 ! Call the handler. The %o's
and lwp_arg have been set up.
154 ldx [%l1
+ G1_OFF
], %g1
! get code
155 set sysent
, %g3
! load address of vector table
156 cmp %g1
, NSYSCALL
! check range
157 sth %g1
, [THREAD_REG
+ T_SYSNUM
] ! save syscall code
158 bgeu
,pn
%ncc
, _syscall_ill
159 sll
%g1
, SYSENT_SHIFT
, %g4
! delay
- get index
161 ldn
[%l4
+ SY_CALLC
], %g3
! load system call handler
163 call
%g3
! call system call handler
166 ! If handler returns two ints
, then we need to split the
64-bit
167 ! return value in
%o0 into
%o0
and %o1
169 lduh
[%l4
+ SY_FLAGS
], %l4
! load sy_flags
170 andcc
%l4
, SE_32RVAL2
, %g0
! check for
2 x
32-bit
173 srl
%o0
, 0, %o1
! lower
32-bits into
%o1
174 srlx
%o0
, 32, %o0
! upper
32-bits into
%o0
179 ! make
trap trace entry for return
- helps in debugging
182 andn
%g5
, PSTATE_IE | PSTATE_AM
, %g4
183 wrpr
%g0
, %g4
, %pstate
! disable interrupt
184 TRACE_PTR
(%g4
, %g2
) ! get trace pointer
185 GET_TRACE_TICK
(%g2
, %g3
)
186 stxa
%g2
, [%g4
+ TRAP_ENT_TICK
]%asi
187 lduh
[THREAD_REG
+ T_SYSNUM
], %g2
188 TRACE_SAVE_TL_VAL
(%g4
, %g2
)
189 TRACE_SAVE_GL_VAL
(%g4
, %g0
)
190 mov TT_SC_RET
, %g2
! system call return code
191 stha
%g2
, [%g4
+ TRAP_ENT_TT
]%asi
192 ldn
[%l1
+ nPC_OFF
], %g2
! get saved npc
(new pc
)
193 stna
%g2
, [%g4
+ TRAP_ENT_TPC
]%asi
194 ldx [%l1
+ TSTATE_OFF
], %g2
! get saved tstate
195 stxa
%g2
, [%g4
+ TRAP_ENT_TSTATE
]%asi
196 stna
%sp
, [%g4
+ TRAP_ENT_SP
]%asi
197 stna THREAD_REG
, [%g4
+ TRAP_ENT_TR
]%asi
198 stna
%o0
, [%g4
+ TRAP_ENT_F1
]%asi
199 stna
%o1
, [%g4
+ TRAP_ENT_F2
]%asi
200 stna
%g0
, [%g4
+ TRAP_ENT_F3
]%asi
201 stna
%g0
, [%g4
+ TRAP_ENT_F4
]%asi
202 TRACE_NEXT
(%g4
, %g2
, %g3
) ! set new trace pointer
203 wrpr
%g0
, %g5
, %pstate
! enable interrupt
204 #endif /* TRAPTRACE */
206 ! Check for post-syscall processing.
207 ! This tests all members of the union containing t_astflag
, t_post_sys
,
208 ! and t_sig_check with one test.
210 ld [THREAD_REG
+ T_POST_SYS_AST
], %g1
212 sethi
%hi
(syscalltrace
), %g4
213 ld [%g4
+ %lo
(syscalltrace
)], %g4
214 orcc
%g4
, %g1
, %g0
! OR in syscalltrace
216 tst
%g1
! need post-processing?
217 #endif /* SYSCALLTRACE */
218 bnz
,pn
%icc
, _syscall_post
! yes
- post_syscall
or AST set
220 stb %g1
, [%l2
+ LWP_STATE
] ! set lwp_state
221 stx %o0
, [%l1
+ O0_OFF
] ! set rp-
>r_o0
222 stx %o1
, [%l1
+ O1_OFF
] ! set rp-
>r_o1
223 clrh
[THREAD_REG
+ T_SYSNUM
] ! clear syscall code
224 ldx [%l1
+ TSTATE_OFF
], %g1
! get saved tstate
225 ldn
[%l1
+ nPC_OFF
], %g2
! get saved npc
(new pc
)
227 sllx
%g3
, TSTATE_CCR_SHIFT
, %g3
228 add %g2
, 4, %g4
! calc new npc
229 andn
%g1
, %g3
, %g1
! clear carry bit for no error
230 stn
%g2
, [%l1
+ PC_OFF
]
231 stn
%g4
, [%l1
+ nPC_OFF
]
232 stx %g1
, [%l1
+ TSTATE_OFF
]
234 ! Switch mstate back on the way out
243 ldx [%l1
+ G1_OFF
], %g1
244 call pre_syscall
! abort
= pre_syscall
(arg0
)
245 sth %g1
, [THREAD_REG
+ T_SYSNUM
]
247 brnz
,pn
%o0
, _syscall_post
! did it abort?
249 ldx [%l1
+ O0_OFF
], %o0
! reload args
250 ldx [%l1
+ O1_OFF
], %o1
251 ldx [%l1
+ O2_OFF
], %o2
252 ldx [%l1
+ O3_OFF
], %o3
253 ldx [%l1
+ O4_OFF
], %o4
255 ldx [%l1
+ O5_OFF
], %o5
258 ! Floating-point
trap was pending at start of system call.
263 andn
%l3
, FP_TRAPPED
, %l3
264 st %l3
, [%sp
+ STACK_BIAS
+ MPCB_FLAGS
] ! clear FP_TRAPPED
265 jmp
%l0
+ 8 ! return to user_rtt
266 clrh
[THREAD_REG
+ T_SYSNUM
] ! clear syscall code
269 ! illegal system call
- syscall number out of range
275 ! Post-syscall with special processing needed.
278 call post_syscall
! post_syscall
(rvals
)
280 jmp
%l0
+ 8 ! return to user_rtt
282 SET_SIZE
(syscall_trap
)
286 * System call trap handler for ILP32 processes.
288 * We branch here from sys_trap when a system call occurs.
294 * %l0 = saved return address
298 ENTRY_NP
(syscall_trap32
)
299 ldx [THREAD_REG
+ T_CPU
], %g1
! get cpu pointer
300 mov
%o7
, %l0
! save return addr
303 ! If the trapping thread has the address mask bit clear
, then it
's
304 ! a 64-bit process, and has no business calling 32-bit syscalls.
306 ldx [%o0 + TSTATE_OFF], %l1 ! saved %tstate.am is that
307 andcc %l1, TSTATE_AM, %l1 ! of the trapping proc
308 be,pn %xcc, _syscall_ill32 !
309 mov %o0, %l1 ! save reg pointer
310 srl %i0, 0, %o0 ! copy 1st arg, clear high bits
311 srl %i1, 0, %o1 ! copy 2nd arg, clear high bits
312 ldx [%g1 + CPU_STATS_SYS_SYSCALL], %g2
313 inc %g2 ! cpu_stats.sys.syscall++
314 stx %g2, [%g1 + CPU_STATS_SYS_SYSCALL]
317 ! Set new state for LWP
319 ldx [THREAD_REG + T_LWP], %l2
321 srl %i2, 0, %o2 ! copy 3rd arg, clear high bits
322 stb %g3, [%l2 + LWP_STATE]
323 srl %i3, 0, %o3 ! copy 4th arg, clear high bits
324 ldx [%l2 + LWP_RU_SYSC], %g2 ! pesky statistics
325 srl %i4, 0, %o4 ! copy 5th arg, clear high bits
327 stx %g2, [%l2 + LWP_RU_SYSC]
328 srl %i5, 0, %o5 ! copy 6th arg, clear high bits
329 ! args for direct syscalls now set up
333 ! make trap trace entry - helps in debugging
336 andn %l3, PSTATE_IE | PSTATE_AM, %g3
337 wrpr %g0, %g3, %pstate ! disable interrupt
338 TRACE_PTR(%g3, %g2) ! get trace pointer
339 GET_TRACE_TICK(%g1, %g2)
340 stxa %g1, [%g3 + TRAP_ENT_TICK]%asi
341 ldx [%l1 + G1_OFF], %g1 ! get syscall code
342 TRACE_SAVE_TL_VAL(%g3, %g1)
343 TRACE_SAVE_GL_VAL(%g3, %g0)
345 stha %g2, [%g3 + TRAP_ENT_TT]%asi
346 stxa %g7, [%g3 + TRAP_ENT_TSTATE]%asi ! save thread in tstate space
347 stna %sp, [%g3 + TRAP_ENT_SP]%asi
348 stna %o0, [%g3 + TRAP_ENT_F1]%asi
349 stna %o1, [%g3 + TRAP_ENT_F2]%asi
350 stna %o2, [%g3 + TRAP_ENT_F3]%asi
351 stna %o3, [%g3 + TRAP_ENT_F4]%asi
352 stna %o4, [%g3 + TRAP_ENT_TPC]%asi
353 stna %o5, [%g3 + TRAP_ENT_TR]%asi
354 TRACE_NEXT(%g3, %g2, %g1) ! set new trace pointer
355 wrpr %g0, %l3, %pstate ! enable interrupt
356 #endif /* TRAPTRACE */
359 ! Test for pre-system-call handling
361 ldub [THREAD_REG + T_PRE_SYS], %g3 ! pre-syscall proc?
363 sethi %hi(syscalltrace), %g4
364 ld [%g4 + %lo(syscalltrace)], %g4
365 orcc %g3, %g4, %g0 ! pre_syscall OR syscalltrace?
367 tst %g3 ! is pre_syscall flag set?
368 #endif /* SYSCALLTRACE */
369 bnz,pn %icc, _syscall_pre32 ! yes - pre_syscall needed
372 ! Fast path invocation of new_mstate
377 lduw [%l1 + O0_OFF + 4], %o0 ! reload 32-bit args
378 lduw [%l1 + O1_OFF + 4], %o1
379 lduw [%l1 + O2_OFF + 4], %o2
380 lduw [%l1 + O3_OFF + 4], %o3
381 lduw [%l1 + O4_OFF + 4], %o4
382 lduw [%l1 + O5_OFF + 4], %o5
387 ! Call the handler. The %o's have been set up.
389 lduw
[%l1
+ G1_OFF
+ 4], %g1
! get
32-bit code
390 set sysent32
, %g3
! load address of vector table
391 cmp %g1
, NSYSCALL
! check range
392 sth %g1
, [THREAD_REG
+ T_SYSNUM
] ! save syscall code
393 bgeu
,pn
%ncc
, _syscall_ill32
394 sll
%g1
, SYSENT_SHIFT
, %g4
! delay
- get index
395 add %g3
, %g4
, %g5
! g5
= addr of sysentry
396 ldx [%g5
+ SY_CALLC
], %g3
! load system call handler
398 brnz
,a,pt
%g1
, 4f
! check for indir
()
399 mov
%g5
, %l4
! save addr of sysentry
401 ! Yuck. If
%g1 is zero
, that means we
're doing a syscall() via the
402 ! indirect system call. That means we have to check the
403 ! flags of the targetted system call, not the indirect system call
404 ! itself. See return value handling code below.
406 set sysent32, %l4 ! load address of vector table
407 cmp %o0, NSYSCALL ! check range
408 bgeu,pn %ncc, 4f ! out of range, let C handle it
409 sll %o0, SYSENT_SHIFT, %g4 ! delay - get index
410 add %g4, %l4, %l4 ! compute & save addr of sysent
412 call %g3 ! call system call handler
416 ! If handler returns long long then we need to split the 64 bit
417 ! return value in %o0 into %o0 and %o1 for ILP32 clients.
419 lduh [%l4 + SY_FLAGS], %g4 ! load sy_flags
420 andcc %g4, SE_64RVAL | SE_32RVAL2, %g0 ! check for 64-bit return
422 srl %o0, 0, %o0 ! 32-bit only
423 srl %o0, 0, %o1 ! lower 32 bits into %o1
424 srlx %o0, 32, %o0 ! upper 32 bits into %o0
429 ! make trap trace entry for return - helps in debugging
432 andn %g5, PSTATE_IE | PSTATE_AM, %g4
433 wrpr %g0, %g4, %pstate ! disable interrupt
434 TRACE_PTR(%g4, %g2) ! get trace pointer
435 GET_TRACE_TICK(%g2, %g3)
436 stxa %g2, [%g4 + TRAP_ENT_TICK]%asi
437 lduh [THREAD_REG + T_SYSNUM], %g2
438 TRACE_SAVE_TL_VAL(%g4, %g2)
439 TRACE_SAVE_GL_VAL(%g4, %g0)
440 mov TT_SC_RET, %g2 ! system call return code
441 stha %g2, [%g4 + TRAP_ENT_TT]%asi
442 ldx [%l1 + nPC_OFF], %g2 ! get saved npc (new pc)
443 stna %g2, [%g4 + TRAP_ENT_TPC]%asi
444 ldx [%l1 + TSTATE_OFF], %g2 ! get saved tstate
445 stxa %g2, [%g4 + TRAP_ENT_TSTATE]%asi
446 stna %sp, [%g4 + TRAP_ENT_SP]%asi
447 stna THREAD_REG, [%g4 + TRAP_ENT_TR]%asi
448 stna %o0, [%g4 + TRAP_ENT_F1]%asi
449 stna %o1, [%g4 + TRAP_ENT_F2]%asi
450 stna %g0, [%g4 + TRAP_ENT_F3]%asi
451 stna %g0, [%g4 + TRAP_ENT_F4]%asi
452 TRACE_NEXT(%g4, %g2, %g3) ! set new trace pointer
453 wrpr %g0, %g5, %pstate ! enable interrupt
454 #endif /* TRAPTRACE */
456 ! Check for post-syscall processing.
457 ! This tests all members of the union containing t_astflag, t_post_sys,
458 ! and t_sig_check with one test.
460 ld [THREAD_REG + T_POST_SYS_AST], %g1
462 sethi %hi(syscalltrace), %g4
463 ld [%g4 + %lo(syscalltrace)], %g4
464 orcc %g4, %g1, %g0 ! OR in syscalltrace
466 tst %g1 ! need post-processing?
467 #endif /* SYSCALLTRACE */
468 bnz,pn %icc, _syscall_post32 ! yes - post_syscall or AST set
470 stb %g1, [%l2 + LWP_STATE] ! set lwp_state
471 stx %o0, [%l1 + O0_OFF] ! set rp->r_o0
472 stx %o1, [%l1 + O1_OFF] ! set rp->r_o1
473 clrh [THREAD_REG + T_SYSNUM] ! clear syscall code
474 ldx [%l1 + TSTATE_OFF], %g1 ! get saved tstate
475 ldx [%l1 + nPC_OFF], %g2 ! get saved npc (new pc)
477 sllx %g3, TSTATE_CCR_SHIFT, %g3
478 add %g2, 4, %g4 ! calc new npc
479 andn %g1, %g3, %g1 ! clear carry bit for no error
480 stx %g2, [%l1 + PC_OFF]
481 stx %g4, [%l1 + nPC_OFF]
482 stx %g1, [%l1 + TSTATE_OFF]
484 ! fast path outbound microstate accounting call
494 ldx [%l1 + G1_OFF], %g1
495 call pre_syscall ! abort = pre_syscall(arg0)
496 sth %g1, [THREAD_REG + T_SYSNUM]
498 brnz,pn %o0, _syscall_post32 ! did it abort?
500 lduw [%l1 + O0_OFF + 4], %o0 ! reload 32-bit args
501 lduw [%l1 + O1_OFF + 4], %o1
502 lduw [%l1 + O2_OFF + 4], %o2
503 lduw [%l1 + O3_OFF + 4], %o3
504 lduw [%l1 + O4_OFF + 4], %o4
506 lduw [%l1 + O5_OFF + 4], %o5
509 ! Floating-point trap was pending at start of system call.
514 andn %l3, FP_TRAPPED, %l3
515 st %l3, [%sp + STACK_BIAS + MPCB_FLAGS] ! clear FP_TRAPPED
516 jmp %l0 + 8 ! return to user_rtt
517 clrh [THREAD_REG + T_SYSNUM] ! clear syscall code
520 ! illegal system call - syscall number out of range
526 ! Post-syscall with special processing needed.
529 call post_syscall ! post_syscall(rvals)
531 jmp %l0 + 8 ! return to user_rtt
533 SET_SIZE(syscall_trap32)
538 * lwp_rtt - start execution in newly created LWP.
539 * Here with t_post_sys set by lwp_create, and lwp_eosys == JUSTRETURN,
540 * so that post_syscall() will run and the registers will
541 * simply be restored.
542 * This must go out through sys_rtt instead of syscall_rtt.
544 ENTRY_NP(lwp_rtt_initial)
545 ldn [THREAD_REG + T_STACK], %l7
546 call __dtrace_probe___proc_start
547 sub %l7, STACK_BIAS, %sp
551 ldn [THREAD_REG + T_STACK], %l7
552 sub %l7, STACK_BIAS, %sp
554 call __dtrace_probe___proc_lwp__start
556 call dtrace_systrace_rtt
557 add %sp, REGOFF + STACK_BIAS, %l7
558 ldx [%l7 + O0_OFF], %o0
560 ldx [%l7 + O1_OFF], %o1
561 ba,a,pt %xcc, user_rtt
563 SET_SIZE(lwp_rtt_initial)