]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/cddl/dev/dtrace/amd64/dtrace_asm.S
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / cddl / dev / dtrace / amd64 / dtrace_asm.S
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
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  * Portions Copyright 2008 John Birrell <jb@freebsd.org>
22  *
23  * $FreeBSD$
24  *
25  */
26 /*
27  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30
31 #define _ASM
32
33 #include <machine/asmacros.h>
34 #include <sys/cpuvar_defs.h>
35 #include <sys/dtrace.h>
36
37 #include "assym.s"
38
39 #define INTR_POP                                \
40         MEXITCOUNT;                             \
41         movq    TF_RDI(%rsp),%rdi;              \
42         movq    TF_RSI(%rsp),%rsi;              \
43         movq    TF_RDX(%rsp),%rdx;              \
44         movq    TF_RCX(%rsp),%rcx;              \
45         movq    TF_R8(%rsp),%r8;                \
46         movq    TF_R9(%rsp),%r9;                \
47         movq    TF_RAX(%rsp),%rax;              \
48         movq    TF_RBX(%rsp),%rbx;              \
49         movq    TF_RBP(%rsp),%rbp;              \
50         movq    TF_R10(%rsp),%r10;              \
51         movq    TF_R11(%rsp),%r11;              \
52         movq    TF_R12(%rsp),%r12;              \
53         movq    TF_R13(%rsp),%r13;              \
54         movq    TF_R14(%rsp),%r14;              \
55         movq    TF_R15(%rsp),%r15;              \
56         testb   $SEL_RPL_MASK,TF_CS(%rsp);      \
57         jz      1f;                             \
58         cli;                                    \
59         swapgs;                                 \
60 1:      addq    $TF_RIP,%rsp;
61
62
63         .globl  calltrap
64         .type   calltrap,@function
65         ENTRY(dtrace_invop_start)
66
67         /*
68          * #BP traps with %rip set to the next address. We need to decrement
69          * the value to indicate the address of the int3 (0xcc) instruction
70          * that we substituted.
71          */
72         movq    TF_RIP(%rsp), %rdi
73         decq    %rdi
74         movq    TF_RSP(%rsp), %rsi
75         movq    TF_RAX(%rsp), %rdx
76         pushq   (%rsi)
77         movq    %rsp, %rsi
78         call    dtrace_invop
79         ALTENTRY(dtrace_invop_callsite)
80         addq    $8, %rsp
81         cmpl    $DTRACE_INVOP_PUSHL_EBP, %eax
82         je      bp_push
83         cmpl    $DTRACE_INVOP_LEAVE, %eax
84         je      bp_leave
85         cmpl    $DTRACE_INVOP_NOP, %eax
86         je      bp_nop
87         cmpl    $DTRACE_INVOP_RET, %eax
88         je      bp_ret
89
90         /* When all else fails handle the trap in the usual way. */
91         jmpq    *dtrace_invop_calltrap_addr
92
93 bp_push:
94         /*
95          * We must emulate a "pushq %rbp".  To do this, we pull the stack
96          * down 8 bytes, and then store the base pointer.
97          */
98         INTR_POP
99         subq    $16, %rsp               /* make room for %rbp */
100         pushq   %rax                    /* push temp */
101         movq    24(%rsp), %rax          /* load calling RIP */
102         movq    %rax, 8(%rsp)           /* store calling RIP */
103         movq    32(%rsp), %rax          /* load calling CS */
104         movq    %rax, 16(%rsp)          /* store calling CS */
105         movq    40(%rsp), %rax          /* load calling RFLAGS */
106         movq    %rax, 24(%rsp)          /* store calling RFLAGS */
107         movq    48(%rsp), %rax          /* load calling RSP */
108         subq    $8, %rax                /* make room for %rbp */
109         movq    %rax, 32(%rsp)          /* store calling RSP */
110         movq    56(%rsp), %rax          /* load calling SS */
111         movq    %rax, 40(%rsp)          /* store calling SS */
112         movq    32(%rsp), %rax          /* reload calling RSP */
113         movq    %rbp, (%rax)            /* store %rbp there */
114         popq    %rax                    /* pop off temp */
115         iretq                           /* return from interrupt */
116         /*NOTREACHED*/
117
118 bp_leave:
119         /*
120          * We must emulate a "leave", which is the same as a "movq %rbp, %rsp"
121          * followed by a "popq %rbp".  This is quite a bit simpler on amd64
122          * than it is on i386 -- we can exploit the fact that the %rsp is
123          * explicitly saved to effect the pop without having to reshuffle
124          * the other data pushed for the trap.
125          */
126         INTR_POP
127         pushq   %rax                    /* push temp */
128         movq    8(%rsp), %rax           /* load calling RIP */
129         movq    %rax, 8(%rsp)           /* store calling RIP */
130         movq    (%rbp), %rax            /* get new %rbp */
131         addq    $8, %rbp                /* adjust new %rsp */
132         movq    %rbp, 32(%rsp)          /* store new %rsp */
133         movq    %rax, %rbp              /* set new %rbp */
134         popq    %rax                    /* pop off temp */
135         iretq                           /* return from interrupt */
136         /*NOTREACHED*/
137
138 bp_nop:
139         /* We must emulate a "nop". */
140         INTR_POP
141         iretq
142         /*NOTREACHED*/
143
144 bp_ret:
145         INTR_POP
146         pushq   %rax                    /* push temp */
147         movq    32(%rsp), %rax          /* load %rsp */
148         movq    (%rax), %rax            /* load calling RIP */
149         movq    %rax, 8(%rsp)           /* store calling RIP */
150         addq    $8, 32(%rsp)            /* adjust new %rsp */
151         popq    %rax                    /* pop off temp */
152         iretq                           /* return from interrupt */
153         /*NOTREACHED*/
154
155         END(dtrace_invop_start)
156
157 /*
158 void dtrace_invop_init(void)
159 */
160         ENTRY(dtrace_invop_init)
161         movq    $dtrace_invop_start, dtrace_invop_jump_addr(%rip)
162         ret
163         END(dtrace_invop_init)
164
165 /*
166 void dtrace_invop_uninit(void)
167 */
168         ENTRY(dtrace_invop_uninit)
169         movq    $0, dtrace_invop_jump_addr(%rip)
170         ret
171         END(dtrace_invop_uninit)
172
173 /*
174 greg_t dtrace_getfp(void)
175 */
176         ENTRY(dtrace_getfp)
177         movq    %rbp, %rax
178         ret
179         END(dtrace_getfp)
180
181 /*
182 uint32_t
183 dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
184 */
185         ENTRY(dtrace_cas32)
186         movl    %esi, %eax
187         lock
188         cmpxchgl %edx, (%rdi)
189         ret
190         END(dtrace_cas32)
191
192 /*
193 void *
194 dtrace_casptr(void *target, void *cmp, void *new)
195 */
196         ENTRY(dtrace_casptr)
197         movq    %rsi, %rax
198         lock
199         cmpxchgq %rdx, (%rdi)
200         ret
201         END(dtrace_casptr)
202
203 /*
204 uintptr_t
205 dtrace_caller(int aframes)
206 */
207         ENTRY(dtrace_caller)
208         movq    $-1, %rax
209         ret
210         END(dtrace_caller)
211
212 /*
213 void
214 dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
215 */
216         ENTRY(dtrace_copy)
217         pushq   %rbp
218         movq    %rsp, %rbp
219
220         xchgq   %rdi, %rsi              /* make %rsi source, %rdi dest */
221         movq    %rdx, %rcx              /* load count */
222         repz                            /* repeat for count ... */
223         smovb                           /*   move from %ds:rsi to %ed:rdi */
224         leave
225         ret
226         END(dtrace_copy)
227
228 /*
229 void
230 dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
231     volatile uint16_t *flags)
232 */
233         ENTRY(dtrace_copystr)
234         pushq   %rbp
235         movq    %rsp, %rbp
236
237 0:
238         movb    (%rdi), %al             /* load from source */
239         movb    %al, (%rsi)             /* store to destination */
240         addq    $1, %rdi                /* increment source pointer */
241         addq    $1, %rsi                /* increment destination pointer */
242         subq    $1, %rdx                /* decrement remaining count */
243         cmpb    $0, %al
244         je      2f
245         testq   $0xfff, %rdx            /* test if count is 4k-aligned */
246         jnz     1f                      /* if not, continue with copying */
247         testq   $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */
248         jnz     2f
249 1:
250         cmpq    $0, %rdx
251         jne     0b
252 2:
253         leave
254         ret
255
256         END(dtrace_copystr)
257
258 /*
259 uintptr_t
260 dtrace_fulword(void *addr)
261 */
262         ENTRY(dtrace_fulword)
263         movq    (%rdi), %rax
264         ret
265         END(dtrace_fulword)
266
267 /*
268 uint8_t
269 dtrace_fuword8_nocheck(void *addr)
270 */
271         ENTRY(dtrace_fuword8_nocheck)
272         xorq    %rax, %rax
273         movb    (%rdi), %al
274         ret
275         END(dtrace_fuword8_nocheck)
276
277 /*
278 uint16_t
279 dtrace_fuword16_nocheck(void *addr)
280 */
281         ENTRY(dtrace_fuword16_nocheck)
282         xorq    %rax, %rax
283         movw    (%rdi), %ax
284         ret
285         END(dtrace_fuword16_nocheck)
286
287 /*
288 uint32_t
289 dtrace_fuword32_nocheck(void *addr)
290 */
291         ENTRY(dtrace_fuword32_nocheck)
292         xorq    %rax, %rax
293         movl    (%rdi), %eax
294         ret
295         END(dtrace_fuword32_nocheck)
296
297 /*
298 uint64_t
299 dtrace_fuword64_nocheck(void *addr)
300 */
301         ENTRY(dtrace_fuword64_nocheck)
302         movq    (%rdi), %rax
303         ret
304         END(dtrace_fuword64_nocheck)
305
306 /*
307 void
308 dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
309     int fault, int fltoffs, uintptr_t illval)
310 */
311         ENTRY(dtrace_probe_error)
312         pushq   %rbp
313         movq    %rsp, %rbp
314         subq    $0x8, %rsp
315         movq    %r9, (%rsp)
316         movq    %r8, %r9
317         movq    %rcx, %r8
318         movq    %rdx, %rcx
319         movq    %rsi, %rdx
320         movq    %rdi, %rsi
321         movl    dtrace_probeid_error(%rip), %edi
322         call    dtrace_probe
323         addq    $0x8, %rsp
324         leave
325         ret
326         END(dtrace_probe_error)
327
328 /*
329 void
330 dtrace_membar_producer(void)
331 */
332         ENTRY(dtrace_membar_producer)
333         rep;    ret     /* use 2 byte return instruction when branch target */
334                         /* AMD Software Optimization Guide - Section 6.2 */
335         END(dtrace_membar_producer)
336
337 /*
338 void
339 dtrace_membar_consumer(void)
340 */
341         ENTRY(dtrace_membar_consumer)
342         rep;    ret     /* use 2 byte return instruction when branch target */
343                         /* AMD Software Optimization Guide - Section 6.2 */
344         END(dtrace_membar_consumer)
345
346 /*
347 dtrace_icookie_t
348 dtrace_interrupt_disable(void)
349 */
350         ENTRY(dtrace_interrupt_disable)
351         pushfq
352         popq    %rax
353         cli
354         ret
355         END(dtrace_interrupt_disable)
356
357 /*
358 void
359 dtrace_interrupt_enable(dtrace_icookie_t cookie)
360 */
361         ENTRY(dtrace_interrupt_enable)
362         pushq   %rdi
363         popfq
364         ret
365         END(dtrace_interrupt_enable)