xref: /freebsd/sys/cddl/dev/dtrace/i386/dtrace_asm.S (revision 911f0260390e18cf85f3dbf2c719b593efdc1e3c)
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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * $FreeBSD$
23 */
24/*
25 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26 * Use is subject to license terms.
27 */
28
29#define _ASM
30
31#include <machine/asmacros.h>
32#include <sys/cpuvar_defs.h>
33#include <sys/dtrace.h>
34
35#include "assym.inc"
36
37	ENTRY(dtrace_invop_start)
38
39	pushl	%eax			/* push %eax -- may be return value */
40	pushl	%esp			/* push stack pointer */
41	subl	$8, (%esp)		/* skip first arg and segment regs */
42	pushl	40(%esp)		/* push calling EIP */
43
44	/*
45	 * Call dtrace_invop to let it check if the exception was
46	 * a fbt one. The return value in %eax will tell us what
47	 * dtrace_invop wants us to do.
48	 */
49	call	dtrace_invop
50	ALTENTRY(dtrace_invop_callsite)
51	addl	$12, %esp
52	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
53	je	invop_push
54	cmpl	$DTRACE_INVOP_POPL_EBP, %eax
55	je	invop_pop
56	cmpl	$DTRACE_INVOP_LEAVE, %eax
57	je	invop_leave
58	cmpl	$DTRACE_INVOP_NOP, %eax
59	je	invop_nop
60
61	/* When all else fails handle the trap in the usual way. */
62	jmpl	*dtrace_invop_calltrap_addr
63
64invop_push:
65	/*
66	 * We must emulate a "pushl %ebp".  To do this, we pull the stack
67	 * down 4 bytes, and then store the base pointer.
68	 */
69	popal
70	subl	$4, %esp		/* make room for %ebp */
71	pushl	%eax			/* push temp */
72	movl	8(%esp), %eax		/* load calling EIP */
73	incl	%eax			/* increment over LOCK prefix */
74	movl	%eax, 4(%esp)		/* store calling EIP */
75	movl	12(%esp), %eax		/* load calling CS */
76	movl	%eax, 8(%esp)		/* store calling CS */
77	movl	16(%esp), %eax		/* load calling EFLAGS */
78	movl	%eax, 12(%esp)		/* store calling EFLAGS */
79	movl	%ebp, 16(%esp)		/* push %ebp */
80	popl	%eax			/* pop off temp */
81	iret				/* Return from interrupt. */
82invop_pop:
83	/*
84	 * We must emulate a "popl %ebp".  To do this, we do the opposite of
85	 * the above:  we remove the %ebp from the stack, and squeeze up the
86	 * saved state from the trap.
87	 */
88	popal
89	pushl	%eax			/* push temp */
90	movl	16(%esp), %ebp		/* pop %ebp */
91	movl	12(%esp), %eax		/* load calling EFLAGS */
92	movl	%eax, 16(%esp)		/* store calling EFLAGS */
93	movl	8(%esp), %eax		/* load calling CS */
94	movl	%eax, 12(%esp)		/* store calling CS */
95	movl	4(%esp), %eax		/* load calling EIP */
96	incl	%eax			/* increment over LOCK prefix */
97	movl	%eax, 8(%esp)		/* store calling EIP */
98	popl	%eax			/* pop off temp */
99	addl	$4, %esp		/* adjust stack pointer */
100	iret				/* Return from interrupt. */
101invop_leave:
102	/*
103	 * We must emulate a "leave", which is the same as a "movl %ebp, %esp"
104	 * followed by a "popl %ebp".  This looks similar to the above, but
105	 * requires two temporaries:  one for the new base pointer, and one
106	 * for the staging register.
107	 */
108	popa
109	pushl	%eax			/* push temp */
110	pushl	%ebx			/* push temp */
111	movl	%ebp, %ebx		/* set temp to old %ebp */
112	movl	(%ebx), %ebp		/* pop %ebp */
113	movl	16(%esp), %eax		/* load calling EFLAGS */
114	movl	%eax, (%ebx)		/* store calling EFLAGS */
115	movl	12(%esp), %eax		/* load calling CS */
116	movl	%eax, -4(%ebx)		/* store calling CS */
117	movl	8(%esp), %eax		/* load calling EIP */
118	incl	%eax			/* increment over LOCK prefix */
119	movl	%eax, -8(%ebx)		/* store calling EIP */
120	subl	$8, %ebx		/* adjust for three pushes, one pop */
121	movl	%ebx, 8(%esp)		/* temporarily store new %esp */
122	popl	%ebx			/* pop off temp */
123	popl	%eax			/* pop off temp */
124	movl	(%esp), %esp		/* set stack pointer */
125	iret				/* return from interrupt */
126invop_nop:
127	/*
128	 * We must emulate a "nop".  This is obviously not hard:  we need only
129	 * advance the %eip by one.
130	 */
131	popa
132	incl	(%esp)
133	iret				/* return from interrupt */
134
135	END(dtrace_invop_start)
136
137/*
138greg_t dtrace_getfp(void)
139*/
140
141	ENTRY(dtrace_getfp)
142	movl	%ebp, %eax
143	ret
144	END(dtrace_getfp)
145
146/*
147uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
148*/
149
150	ENTRY(dtrace_cas32)
151	ALTENTRY(dtrace_casptr)
152	movl	4(%esp), %edx
153	movl	8(%esp), %eax
154	movl	12(%esp), %ecx
155	lock
156	cmpxchgl %ecx, (%edx)
157	ret
158	END(dtrace_casptr)
159	END(dtrace_cas32)
160
161/*
162uintptr_t dtrace_caller(int aframes)
163*/
164
165	ENTRY(dtrace_caller)
166	movl	$-1, %eax
167	ret
168	END(dtrace_caller)
169
170/*
171void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
172*/
173
174	ENTRY(dtrace_copy)
175	pushl	%ebp
176	movl	%esp, %ebp
177	pushl	%esi
178	pushl	%edi
179
180	movl	8(%ebp), %esi		/* Load source address */
181	movl	12(%ebp), %edi		/* Load destination address */
182	movl	16(%ebp), %ecx		/* Load count */
183	repz				/* Repeat for count... */
184	smovb				/*   move from %ds:si to %es:di */
185
186	popl	%edi
187	popl	%esi
188	movl	%ebp, %esp
189	popl	%ebp
190	ret
191	END(dtrace_copy)
192
193/*
194void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size)
195*/
196
197	ENTRY(dtrace_copystr)
198
199	pushl	%ebp			/* Setup stack frame */
200	movl	%esp, %ebp
201	pushl	%ebx			/* Save registers */
202
203	movl	8(%ebp), %ebx		/* Load source address */
204	movl	12(%ebp), %edx		/* Load destination address */
205	movl	16(%ebp), %ecx		/* Load count */
206
2070:
208	movb	(%ebx), %al		/* Load from source */
209	movb	%al, (%edx)		/* Store to destination */
210	incl	%ebx			/* Increment source pointer */
211	incl	%edx			/* Increment destination pointer */
212	decl	%ecx			/* Decrement remaining count */
213	cmpb	$0, %al
214	je	1f
215	cmpl	$0, %ecx
216	jne	0b
217
2181:
219	popl	%ebx
220	movl	%ebp, %esp
221	popl	%ebp
222	ret
223
224	END(dtrace_copystr)
225
226/*
227uintptr_t dtrace_fulword(void *addr)
228*/
229
230	ENTRY(dtrace_fulword)
231	movl	4(%esp), %ecx
232	xorl	%eax, %eax
233	movl	(%ecx), %eax
234	ret
235	END(dtrace_fulword)
236
237/*
238uint8_t dtrace_fuword8_nocheck(void *addr)
239*/
240
241	ENTRY(dtrace_fuword8_nocheck)
242	movl	4(%esp), %ecx
243	xorl	%eax, %eax
244	movzbl	(%ecx), %eax
245	ret
246	END(dtrace_fuword8_nocheck)
247
248/*
249uint16_t dtrace_fuword16_nocheck(void *addr)
250*/
251
252	ENTRY(dtrace_fuword16_nocheck)
253	movl	4(%esp), %ecx
254	xorl	%eax, %eax
255	movzwl	(%ecx), %eax
256	ret
257	END(dtrace_fuword16_nocheck)
258
259/*
260uint32_t dtrace_fuword32_nocheck(void *addr)
261*/
262
263	ENTRY(dtrace_fuword32_nocheck)
264	movl	4(%esp), %ecx
265	xorl	%eax, %eax
266	movl	(%ecx), %eax
267	ret
268	END(dtrace_fuword32_nocheck)
269
270/*
271uint64_t dtrace_fuword64_nocheck(void *addr)
272*/
273
274	ENTRY(dtrace_fuword64_nocheck)
275	movl	4(%esp), %ecx
276	xorl	%eax, %eax
277	xorl	%edx, %edx
278	movl	(%ecx), %eax
279	movl	4(%ecx), %edx
280	ret
281	END(dtrace_fuword64_nocheck)
282
283/*
284void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)
285*/
286
287	ENTRY(dtrace_probe_error)
288	pushl	%ebp
289	movl	%esp, %ebp
290	pushl	0x1c(%ebp)
291	pushl	0x18(%ebp)
292	pushl	0x14(%ebp)
293	pushl	0x10(%ebp)
294	pushl	0xc(%ebp)
295	pushl	0x8(%ebp)
296	pushl	dtrace_probeid_error
297	call	dtrace_probe
298	movl	%ebp, %esp
299	popl	%ebp
300	ret
301	END(dtrace_probe_error)
302
303/*
304void dtrace_membar_producer(void)
305*/
306
307	ENTRY(dtrace_membar_producer)
308	rep;	ret	/* use 2 byte return instruction when branch target */
309			/* AMD Software Optimization Guide - Section 6.2 */
310	END(dtrace_membar_producer)
311
312/*
313void dtrace_membar_consumer(void)
314*/
315
316	ENTRY(dtrace_membar_consumer)
317	rep;	ret	/* use 2 byte return instruction when branch target */
318			/* AMD Software Optimization Guide - Section 6.2 */
319	END(dtrace_membar_consumer)
320
321/*
322dtrace_icookie_t dtrace_interrupt_disable(void)
323*/
324	ENTRY(dtrace_interrupt_disable)
325	pushfl
326	popl	%eax
327	cli
328	ret
329	END(dtrace_interrupt_disable)
330
331/*
332void dtrace_interrupt_enable(dtrace_icookie_t cookie)
333*/
334	ENTRY(dtrace_interrupt_enable)
335	movl	4(%esp), %eax
336	pushl	%eax
337	popfl
338	ret
339	END(dtrace_interrupt_enable)
340