dtrace_asm.S revision 283676
191094Sdes/*
2115619Sdes * CDDL HEADER START
3174832Sdes *
491094Sdes * The contents of this file are subject to the terms of the
591094Sdes * Common Development and Distribution License (the "License").
691094Sdes * You may not use this file except in compliance with the License.
799158Sdes *
899158Sdes * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
999158Sdes * or http://www.opensolaris.org/os/licensing.
1091094Sdes * See the License for the specific language governing permissions
1191094Sdes * and limitations under the License.
1291094Sdes *
1391094Sdes * When distributing Covered Code, include this CDDL HEADER in each
1491094Sdes * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1591094Sdes * If applicable, add the following below this CDDL HEADER, with the
1691094Sdes * fields enclosed by brackets "[]" replaced with your own identifying
1791094Sdes * information: Portions Copyright [yyyy] [name of copyright owner]
1891094Sdes *
1991094Sdes * CDDL HEADER END
2091094Sdes *
2191094Sdes * Portions Copyright 2008 John Birrell <jb@freebsd.org>
2291094Sdes *
2391094Sdes * $FreeBSD: stable/10/sys/cddl/dev/dtrace/amd64/dtrace_asm.S 283676 2015-05-29 04:01:39Z markj $
2491094Sdes *
2591094Sdes */
2691094Sdes/*
2791094Sdes * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2891094Sdes * Use is subject to license terms.
2991094Sdes */
3091094Sdes
3191094Sdes#define _ASM
3291094Sdes
3391094Sdes#include <machine/asmacros.h>
3491094Sdes#include <sys/cpuvar_defs.h>
35174832Sdes#include <sys/dtrace.h>
3691094Sdes
3791094Sdes#include "assym.s"
3891094Sdes
3991094Sdes#define INTR_POP				\
4091094Sdes	MEXITCOUNT;				\
4191094Sdes	movq	TF_RDI(%rsp),%rdi;		\
4291094Sdes	movq	TF_RSI(%rsp),%rsi;		\
4391094Sdes	movq	TF_RDX(%rsp),%rdx;		\
4491094Sdes	movq	TF_RCX(%rsp),%rcx;		\
4591094Sdes	movq	TF_R8(%rsp),%r8;		\
46107937Sdes	movq	TF_R9(%rsp),%r9;		\
47107937Sdes	movq	TF_RAX(%rsp),%rax;		\
48107937Sdes	movq	TF_RBX(%rsp),%rbx;		\
49107937Sdes	movq	TF_RBP(%rsp),%rbp;		\
50107937Sdes	movq	TF_R10(%rsp),%r10;		\
51107937Sdes	movq	TF_R11(%rsp),%r11;		\
52107937Sdes	movq	TF_R12(%rsp),%r12;		\
53107937Sdes	movq	TF_R13(%rsp),%r13;		\
54107937Sdes	movq	TF_R14(%rsp),%r14;		\
5591094Sdes	movq	TF_R15(%rsp),%r15;		\
5691097Sdes	testb	$SEL_RPL_MASK,TF_CS(%rsp);	\
5791097Sdes	jz	1f;				\
5891094Sdes	cli;					\
5991097Sdes	swapgs;					\
6091094Sdes1:	addq	$TF_RIP,%rsp;
6191097Sdes
6291094Sdes
6391094Sdes	.globl	calltrap
6491094Sdes	.type	calltrap,@function
65174832Sdes	ENTRY(dtrace_invop_start)
6691094Sdes
6791094Sdes	/*
68115619Sdes	 * #BP traps with %rip set to the next address. We need to decrement
6991094Sdes	 * the value to indicate the address of the int3 (0xcc) instruction
7091094Sdes	 * that we substituted.
7191094Sdes	 */
7291094Sdes	movq	TF_RIP(%rsp), %rdi
7391684Sdes	decq	%rdi
7491094Sdes	movq	TF_RSP(%rsp), %rsi
7591094Sdes	movq	TF_RAX(%rsp), %rdx
7691094Sdes	pushq	(%rsi)
7791094Sdes	movq	%rsp, %rsi
7891094Sdes	call	dtrace_invop
7991094Sdes	ALTENTRY(dtrace_invop_callsite)
8091100Sdes	addq	$8, %rsp
8191094Sdes	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
8291094Sdes	je	bp_push
8391094Sdes	cmpl	$DTRACE_INVOP_LEAVE, %eax
8491094Sdes	je	bp_leave
8591830Sdes	cmpl	$DTRACE_INVOP_NOP, %eax
8691830Sdes	je	bp_nop
8791094Sdes	cmpl	$DTRACE_INVOP_RET, %eax
8891830Sdes	je	bp_ret
8991094Sdes
9091094Sdes	/* When all else fails handle the trap in the usual way. */
9191094Sdes	jmpq	*dtrace_invop_calltrap_addr
9291094Sdes
9391094Sdesbp_push:
9491094Sdes	/*
9591094Sdes	 * We must emulate a "pushq %rbp".  To do this, we pull the stack
9691094Sdes	 * down 8 bytes, and then store the base pointer.
9791094Sdes	 */
9891094Sdes	INTR_POP
9991094Sdes	subq	$16, %rsp		/* make room for %rbp */
10091094Sdes	pushq	%rax			/* push temp */
10191094Sdes	movq	24(%rsp), %rax		/* load calling RIP */
10291094Sdes	movq	%rax, 8(%rsp)		/* store calling RIP */
10391094Sdes	movq	32(%rsp), %rax		/* load calling CS */
10491094Sdes	movq	%rax, 16(%rsp)		/* store calling CS */
10591094Sdes	movq	40(%rsp), %rax		/* load calling RFLAGS */
10691094Sdes	movq	%rax, 24(%rsp)		/* store calling RFLAGS */
10791830Sdes	movq	48(%rsp), %rax		/* load calling RSP */
108115619Sdes	subq	$8, %rax		/* make room for %rbp */
109115619Sdes	movq	%rax, 32(%rsp)		/* store calling RSP */
11091094Sdes	movq	56(%rsp), %rax		/* load calling SS */
11191094Sdes	movq	%rax, 40(%rsp)		/* store calling SS */
11291094Sdes	movq	32(%rsp), %rax		/* reload calling RSP */
11391094Sdes	movq	%rbp, (%rax)		/* store %rbp there */
11491094Sdes	popq	%rax			/* pop off temp */
11591094Sdes	iretq				/* return from interrupt */
11691094Sdes	/*NOTREACHED*/
11791094Sdes
11891094Sdesbp_leave:
11991094Sdes	/*
12091094Sdes	 * We must emulate a "leave", which is the same as a "movq %rbp, %rsp"
12191094Sdes	 * followed by a "popq %rbp".  This is quite a bit simpler on amd64
12291094Sdes	 * than it is on i386 -- we can exploit the fact that the %rsp is
12391094Sdes	 * explicitly saved to effect the pop without having to reshuffle
12491094Sdes	 * the other data pushed for the trap.
125116520Sdes	 */
126116520Sdes	INTR_POP
127115619Sdes	pushq	%rax			/* push temp */
128116520Sdes	movq	8(%rsp), %rax		/* load calling RIP */
129115619Sdes	movq	%rax, 8(%rsp)		/* store calling RIP */
13091094Sdes	movq	(%rbp), %rax		/* get new %rbp */
131116520Sdes	addq	$8, %rbp		/* adjust new %rsp */
132115619Sdes	movq	%rbp, 32(%rsp)		/* store new %rsp */
13391094Sdes	movq	%rax, %rbp		/* set new %rbp */
13491094Sdes	popq	%rax			/* pop off temp */
13591094Sdes	iretq				/* return from interrupt */
13691094Sdes	/*NOTREACHED*/
13791094Sdes
13891094Sdesbp_nop:
13991094Sdes	/* We must emulate a "nop". */
14091094Sdes	INTR_POP
14195908Sdes	iretq
14291094Sdes	/*NOTREACHED*/
14391094Sdes
14491094Sdesbp_ret:
145147455Sdes	INTR_POP
14695908Sdes	pushq	%rax			/* push temp */
147147455Sdes	movq	32(%rsp), %rax		/* load %rsp */
148147455Sdes	movq	(%rax), %rax		/* load calling RIP */
14991094Sdes	movq	%rax, 8(%rsp)		/* store calling RIP */
15091100Sdes	addq	$8, 32(%rsp)		/* adjust new %rsp */
15191100Sdes	popq	%rax			/* pop off temp */
15291100Sdes	iretq				/* return from interrupt */
15391100Sdes	/*NOTREACHED*/
154
155	END(dtrace_invop_start)
156
157/*
158void 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/*
166void 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/*
174greg_t dtrace_getfp(void)
175*/
176	ENTRY(dtrace_getfp)
177	movq	%rbp, %rax
178	ret
179	END(dtrace_getfp)
180
181/*
182uint32_t
183dtrace_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/*
193void *
194dtrace_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/*
204uintptr_t
205dtrace_caller(int aframes)
206*/
207	ENTRY(dtrace_caller)
208	movq	$-1, %rax
209	ret
210	END(dtrace_caller)
211
212/*
213void
214dtrace_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/*
229void
230dtrace_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
2370:
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
2491:
250	cmpq	$0, %rdx
251	jne	0b
2522:
253	leave
254	ret
255
256	END(dtrace_copystr)
257
258/*
259uintptr_t
260dtrace_fulword(void *addr)
261*/
262	ENTRY(dtrace_fulword)
263	movq	(%rdi), %rax
264	ret
265	END(dtrace_fulword)
266
267/*
268uint8_t
269dtrace_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/*
278uint16_t
279dtrace_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/*
288uint32_t
289dtrace_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/*
298uint64_t
299dtrace_fuword64_nocheck(void *addr)
300*/
301	ENTRY(dtrace_fuword64_nocheck)
302	movq	(%rdi), %rax
303	ret
304	END(dtrace_fuword64_nocheck)
305
306/*
307void
308dtrace_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/*
329void
330dtrace_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/*
338void
339dtrace_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/*
347dtrace_icookie_t
348dtrace_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/*
358void
359dtrace_interrupt_enable(dtrace_icookie_t cookie)
360*/
361	ENTRY(dtrace_interrupt_enable)
362	pushq	%rdi
363	popfq
364	ret
365	END(dtrace_interrupt_enable)
366