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