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.inc"
38
39 #define INTR_POP \
40 movq TF_RDI(%rsp),%rdi; \
41 movq TF_RSI(%rsp),%rsi; \
42 movq TF_RDX(%rsp),%rdx; \
43 movq TF_RCX(%rsp),%rcx; \
44 movq TF_R8(%rsp),%r8; \
45 movq TF_R9(%rsp),%r9; \
46 movq TF_RAX(%rsp),%rax; \
47 movq TF_RBX(%rsp),%rbx; \
48 movq TF_RBP(%rsp),%rbp; \
49 movq TF_R10(%rsp),%r10; \
50 movq TF_R11(%rsp),%r11; \
51 movq TF_R12(%rsp),%r12; \
52 movq TF_R13(%rsp),%r13; \
53 movq TF_R14(%rsp),%r14; \
54 movq TF_R15(%rsp),%r15; \
55 testb $SEL_RPL_MASK,TF_CS(%rsp); \
56 jz 1f; \
57 cli; \
58 swapgs; \
59 1: addq $TF_RIP,%rsp;
60
61 .globl dtrace_invop_callsite
62 .type dtrace_invop_callsite,@function
63
64 ENTRY(dtrace_invop_start)
65
66 /*
67 * #BP traps with %rip set to the next address. We need to decrement
68 * the value to indicate the address of the int3 (0xcc) instruction
69 * that we substituted.
70 */
71 movq TF_RIP(%rsp), %rdi
72 decq %rdi
73 movq %rsp, %rsi
74
75 /*
76 * Allocate some scratch space to let the invop handler return a value.
77 * This is needed when emulating "call" instructions.
78 */
79 subq $16, %rsp
80 movq %rsp, %rdx
81
82 call dtrace_invop
83 dtrace_invop_callsite:
84 addq $16, %rsp
85
86 cmpl $DTRACE_INVOP_PUSHL_EBP, %eax
87 je bp_push
88 cmpl $DTRACE_INVOP_CALL, %eax
89 je bp_call
90 cmpl $DTRACE_INVOP_LEAVE, %eax
91 je bp_leave
92 cmpl $DTRACE_INVOP_NOP, %eax
93 je bp_nop
94 cmpl $DTRACE_INVOP_RET, %eax
95 je bp_ret
96
97 /* When all else fails handle the trap in the usual way. */
98 jmpq *dtrace_invop_calltrap_addr
99
100 bp_push:
101 /*
102 * We must emulate a "pushq %rbp". To do this, we pull the stack
103 * down 8 bytes, and then store the base pointer.
104 */
105 INTR_POP
106 subq $16, %rsp /* make room for %rbp */
107 pushq %rax /* push temp */
108 movq 24(%rsp), %rax /* load calling RIP */
109 movq %rax, 8(%rsp) /* store calling RIP */
110 movq 32(%rsp), %rax /* load calling CS */
111 movq %rax, 16(%rsp) /* store calling CS */
112 movq 40(%rsp), %rax /* load calling RFLAGS */
113 movq %rax, 24(%rsp) /* store calling RFLAGS */
114 movq 48(%rsp), %rax /* load calling RSP */
115 subq $8, %rax /* make room for %rbp */
116 movq %rax, 32(%rsp) /* store calling RSP */
117 movq 56(%rsp), %rax /* load calling SS */
118 movq %rax, 40(%rsp) /* store calling SS */
119 movq 32(%rsp), %rax /* reload calling RSP */
120 movq %rbp, (%rax) /* store %rbp there */
121 popq %rax /* pop off temp */
122 iretq /* return from interrupt */
123 /*NOTREACHED*/
124
125 bp_call:
126 /*
127 * Emulate a "call" instruction. The invop handler must have already
128 * updated the saved copy of %rip in the register set. It's our job to
129 * pull the hardware-saved registers down to make space for the return
130 * address, which is provided by the invop handler in our scratch
131 * space.
132 */
133 INTR_POP
134 subq $16, %rsp /* make room for %rbp */
135 pushq %rax /* push temp */
136 pushq %rbx /* push temp */
137
138 movq 32(%rsp), %rax /* load calling RIP */
139 movq %rax, 16(%rsp) /* store calling RIP */
140 movq 40(%rsp), %rax /* load calling CS */
141 movq %rax, 24(%rsp) /* store calling CS */
142 movq 48(%rsp), %rax /* load calling RFLAGS */
143 movq %rax, 32(%rsp) /* store calling RFLAGS */
144 movq 56(%rsp), %rax /* load calling RSP */
145 subq $8, %rax /* make room for return address */
146 movq %rax, 40(%rsp) /* store calling RSP */
147 movq 64(%rsp), %rax /* load calling SS */
148 movq %rax, 48(%rsp) /* store calling SS */
149
150 movq -(TF_RIP - 16)(%rsp), %rax /* load return address */
151 movq 40(%rsp), %rbx /* reload calling RSP */
152 movq %rax, (%rbx) /* store return address */
153
154 popq %rbx /* pop temp */
155 popq %rax /* pop temp */
156 iretq /* return from interrupt */
157 /*NOTREACHED*/
158
159 bp_leave:
160 /*
161 * We must emulate a "leave", which is the same as a "movq %rbp, %rsp"
162 * followed by a "popq %rbp". This is quite a bit simpler on amd64
163 * than it is on i386 -- we can exploit the fact that the %rsp is
164 * explicitly saved to effect the pop without having to reshuffle
165 * the other data pushed for the trap.
166 */
167 INTR_POP
168 pushq %rax /* push temp */
169 movq 8(%rsp), %rax /* load calling RIP */
170 movq %rax, 8(%rsp) /* store calling RIP */
171 movq (%rbp), %rax /* get new %rbp */
172 addq $8, %rbp /* adjust new %rsp */
173 movq %rbp, 32(%rsp) /* store new %rsp */
174 movq %rax, %rbp /* set new %rbp */
175 popq %rax /* pop off temp */
176 iretq /* return from interrupt */
177 /*NOTREACHED*/
178
179 bp_nop:
180 /* We must emulate a "nop". */
181 INTR_POP
182 iretq
183 /*NOTREACHED*/
184
185 bp_ret:
186 INTR_POP
187 pushq %rax /* push temp */
188 movq 32(%rsp), %rax /* load %rsp */
189 movq (%rax), %rax /* load calling RIP */
190 movq %rax, 8(%rsp) /* store calling RIP */
191 addq $8, 32(%rsp) /* adjust new %rsp */
192 popq %rax /* pop off temp */
193 iretq /* return from interrupt */
194 /*NOTREACHED*/
195
196 END(dtrace_invop_start)
197
198 /*
199 greg_t dtrace_getfp(void)
200 */
201 ENTRY(dtrace_getfp)
202 movq %rbp, %rax
203 ret
204 END(dtrace_getfp)
205
206 /*
207 uint32_t
208 dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
209 */
210 ENTRY(dtrace_cas32)
211 movl %esi, %eax
212 lock
213 cmpxchgl %edx, (%rdi)
214 ret
215 END(dtrace_cas32)
216
217 /*
218 void *
219 dtrace_casptr(void *target, void *cmp, void *new)
220 */
221 ENTRY(dtrace_casptr)
222 movq %rsi, %rax
223 lock
224 cmpxchgq %rdx, (%rdi)
225 ret
226 END(dtrace_casptr)
227
228 /*
229 uintptr_t
230 dtrace_caller(int aframes)
231 */
232 ENTRY(dtrace_caller)
233 movq $-1, %rax
234 ret
235 END(dtrace_caller)
236
237 /*
238 void
239 dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
240 */
241 ENTRY(dtrace_copy_nosmap)
242 pushq %rbp
243 movq %rsp, %rbp
244
245 xchgq %rdi, %rsi /* make %rsi source, %rdi dest */
246 movq %rdx, %rcx /* load count */
247 repz /* repeat for count ... */
248 smovb /* move from %ds:rsi to %ed:rdi */
249 leave
250 ret
251 END(dtrace_copy_nosmap)
252
253 ENTRY(dtrace_copy_smap)
254 pushq %rbp
255 movq %rsp, %rbp
256
257 xchgq %rdi, %rsi /* make %rsi source, %rdi dest */
258 movq %rdx, %rcx /* load count */
259 stac
260 repz /* repeat for count ... */
261 smovb /* move from %ds:rsi to %ed:rdi */
262 clac
263 leave
264 ret
265 END(dtrace_copy_smap)
266
267 /*
268 void
269 dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
270 volatile uint16_t *flags)
271 */
272 ENTRY(dtrace_copystr_nosmap)
273 pushq %rbp
274 movq %rsp, %rbp
275
276 0:
277 movb (%rdi), %al /* load from source */
278 movb %al, (%rsi) /* store to destination */
279 addq $1, %rdi /* increment source pointer */
280 addq $1, %rsi /* increment destination pointer */
281 subq $1, %rdx /* decrement remaining count */
282 cmpb $0, %al
283 je 2f
284 testq $0xfff, %rdx /* test if count is 4k-aligned */
285 jnz 1f /* if not, continue with copying */
286 testq $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */
287 jnz 2f
288 1:
289 cmpq $0, %rdx
290 jne 0b
291 2:
292 leave
293 ret
294
295 END(dtrace_copystr_nosmap)
296
297 ENTRY(dtrace_copystr_smap)
298 pushq %rbp
299 movq %rsp, %rbp
300
301 stac
302 0:
303 movb (%rdi), %al /* load from source */
304 movb %al, (%rsi) /* store to destination */
305 addq $1, %rdi /* increment source pointer */
306 addq $1, %rsi /* increment destination pointer */
307 subq $1, %rdx /* decrement remaining count */
308 cmpb $0, %al
309 je 2f
310 testq $0xfff, %rdx /* test if count is 4k-aligned */
311 jnz 1f /* if not, continue with copying */
312 testq $CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */
313 jnz 2f
314 1:
315 cmpq $0, %rdx
316 jne 0b
317 2:
318 clac
319 leave
320 ret
321
322 END(dtrace_copystr_smap)
323
324 /*
325 uintptr_t
326 dtrace_fulword(void *addr)
327 */
328 ENTRY(dtrace_fulword_nosmap)
329 movq (%rdi), %rax
330 ret
331 END(dtrace_fulword_nosmap)
332
333 ENTRY(dtrace_fulword_smap)
334 stac
335 movq (%rdi), %rax
336 clac
337 ret
338 END(dtrace_fulword_smap)
339
340 /*
341 uint8_t
342 dtrace_fuword8_nocheck(void *addr)
343 */
344 ENTRY(dtrace_fuword8_nocheck_nosmap)
345 xorq %rax, %rax
346 movb (%rdi), %al
347 ret
348 END(dtrace_fuword8_nocheck_nosmap)
349
350 ENTRY(dtrace_fuword8_nocheck_smap)
351 stac
352 xorq %rax, %rax
353 movb (%rdi), %al
354 clac
355 ret
356 END(dtrace_fuword8_nocheck_smap)
357
358 /*
359 uint16_t
360 dtrace_fuword16_nocheck(void *addr)
361 */
362 ENTRY(dtrace_fuword16_nocheck_nosmap)
363 xorq %rax, %rax
364 movw (%rdi), %ax
365 ret
366 END(dtrace_fuword16_nocheck_nosmap)
367
368 ENTRY(dtrace_fuword16_nocheck_smap)
369 stac
370 xorq %rax, %rax
371 movw (%rdi), %ax
372 clac
373 ret
374 END(dtrace_fuword16_nocheck_smap)
375
376 /*
377 uint32_t
378 dtrace_fuword32_nocheck(void *addr)
379 */
380 ENTRY(dtrace_fuword32_nocheck_nosmap)
381 xorq %rax, %rax
382 movl (%rdi), %eax
383 ret
384 END(dtrace_fuword32_nocheck_nosmap)
385
386 ENTRY(dtrace_fuword32_nocheck_smap)
387 stac
388 xorq %rax, %rax
389 movl (%rdi), %eax
390 clac
391 ret
392 END(dtrace_fuword32_nocheck_smap)
393
394 /*
395 uint64_t
396 dtrace_fuword64_nocheck(void *addr)
397 */
398 ENTRY(dtrace_fuword64_nocheck_nosmap)
399 movq (%rdi), %rax
400 ret
401 END(dtrace_fuword64_nocheck_nosmap)
402
403 ENTRY(dtrace_fuword64_nocheck_smap)
404 stac
405 movq (%rdi), %rax
406 clac
407 ret
408 END(dtrace_fuword64_nocheck_smap)
409
410 /*
411 void
412 dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
413 int fault, int fltoffs, uintptr_t illval)
414 */
415 ENTRY(dtrace_probe_error)
416 pushq %rbp
417 movq %rsp, %rbp
418 subq $0x8, %rsp
419 movq %r9, (%rsp)
420 movq %r8, %r9
421 movq %rcx, %r8
422 movq %rdx, %rcx
423 movq %rsi, %rdx
424 movq %rdi, %rsi
425 movl dtrace_probeid_error(%rip), %edi
426 call dtrace_probe
427 addq $0x8, %rsp
428 leave
429 ret
430 END(dtrace_probe_error)
431
432 /*
433 void
434 dtrace_membar_producer(void)
435 */
436 ENTRY(dtrace_membar_producer)
437 rep; ret /* use 2 byte return instruction when branch target */
438 /* AMD Software Optimization Guide - Section 6.2 */
439 END(dtrace_membar_producer)
440
441 /*
442 void
443 dtrace_membar_consumer(void)
444 */
445 ENTRY(dtrace_membar_consumer)
446 rep; ret /* use 2 byte return instruction when branch target */
447 /* AMD Software Optimization Guide - Section 6.2 */
448 END(dtrace_membar_consumer)
449
450 /*
451 dtrace_icookie_t
452 dtrace_interrupt_disable(void)
453 */
454 ENTRY(dtrace_interrupt_disable)
455 pushfq
456 popq %rax
457 cli
458 ret
459 END(dtrace_interrupt_disable)
460
461 /*
462 void
463 dtrace_interrupt_enable(dtrace_icookie_t cookie)
464 */
465 ENTRY(dtrace_interrupt_enable)
466 pushq %rdi
467 popfq
468 ret
469 END(dtrace_interrupt_enable)
Cache object: 3ca9b1f6f0c0e769ed4d1eb90c578b65
|