xref: /freebsd/sys/cddl/dev/dtrace/i386/dtrace_asm.S (revision f5147e312f43a9050468de539aeafa072caa1a60)
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/*
138void dtrace_invop_init(void)
139*/
140	ENTRY(dtrace_invop_init)
141	movl	$dtrace_invop_start, dtrace_invop_jump_addr
142	ret
143	END(dtrace_invop_init)
144
145/*
146void dtrace_invop_uninit(void)
147*/
148	ENTRY(dtrace_invop_uninit)
149	movl	$0, dtrace_invop_jump_addr
150	ret
151	END(dtrace_invop_uninit)
152
153/*
154greg_t dtrace_getfp(void)
155*/
156
157	ENTRY(dtrace_getfp)
158	movl	%ebp, %eax
159	ret
160	END(dtrace_getfp)
161
162/*
163uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
164*/
165
166	ENTRY(dtrace_cas32)
167	ALTENTRY(dtrace_casptr)
168	movl	4(%esp), %edx
169	movl	8(%esp), %eax
170	movl	12(%esp), %ecx
171	lock
172	cmpxchgl %ecx, (%edx)
173	ret
174	END(dtrace_casptr)
175	END(dtrace_cas32)
176
177/*
178uintptr_t dtrace_caller(int aframes)
179*/
180
181	ENTRY(dtrace_caller)
182	movl	$-1, %eax
183	ret
184	END(dtrace_caller)
185
186/*
187void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
188*/
189
190	ENTRY(dtrace_copy)
191	pushl	%ebp
192	movl	%esp, %ebp
193	pushl	%esi
194	pushl	%edi
195
196	movl	8(%ebp), %esi		/* Load source address */
197	movl	12(%ebp), %edi		/* Load destination address */
198	movl	16(%ebp), %ecx		/* Load count */
199	repz				/* Repeat for count... */
200	smovb				/*   move from %ds:si to %es:di */
201
202	popl	%edi
203	popl	%esi
204	movl	%ebp, %esp
205	popl	%ebp
206	ret
207	END(dtrace_copy)
208
209/*
210void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size)
211*/
212
213	ENTRY(dtrace_copystr)
214
215	pushl	%ebp			/* Setup stack frame */
216	movl	%esp, %ebp
217	pushl	%ebx			/* Save registers */
218
219	movl	8(%ebp), %ebx		/* Load source address */
220	movl	12(%ebp), %edx		/* Load destination address */
221	movl	16(%ebp), %ecx		/* Load count */
222
2230:
224	movb	(%ebx), %al		/* Load from source */
225	movb	%al, (%edx)		/* Store to destination */
226	incl	%ebx			/* Increment source pointer */
227	incl	%edx			/* Increment destination pointer */
228	decl	%ecx			/* Decrement remaining count */
229	cmpb	$0, %al
230	je	1f
231	cmpl	$0, %ecx
232	jne	0b
233
2341:
235	popl	%ebx
236	movl	%ebp, %esp
237	popl	%ebp
238	ret
239
240	END(dtrace_copystr)
241
242/*
243uintptr_t dtrace_fulword(void *addr)
244*/
245
246	ENTRY(dtrace_fulword)
247	movl	4(%esp), %ecx
248	xorl	%eax, %eax
249	movl	(%ecx), %eax
250	ret
251	END(dtrace_fulword)
252
253/*
254uint8_t dtrace_fuword8_nocheck(void *addr)
255*/
256
257	ENTRY(dtrace_fuword8_nocheck)
258	movl	4(%esp), %ecx
259	xorl	%eax, %eax
260	movzbl	(%ecx), %eax
261	ret
262	END(dtrace_fuword8_nocheck)
263
264/*
265uint16_t dtrace_fuword16_nocheck(void *addr)
266*/
267
268	ENTRY(dtrace_fuword16_nocheck)
269	movl	4(%esp), %ecx
270	xorl	%eax, %eax
271	movzwl	(%ecx), %eax
272	ret
273	END(dtrace_fuword16_nocheck)
274
275/*
276uint32_t dtrace_fuword32_nocheck(void *addr)
277*/
278
279	ENTRY(dtrace_fuword32_nocheck)
280	movl	4(%esp), %ecx
281	xorl	%eax, %eax
282	movl	(%ecx), %eax
283	ret
284	END(dtrace_fuword32_nocheck)
285
286/*
287uint64_t dtrace_fuword64_nocheck(void *addr)
288*/
289
290	ENTRY(dtrace_fuword64_nocheck)
291	movl	4(%esp), %ecx
292	xorl	%eax, %eax
293	xorl	%edx, %edx
294	movl	(%ecx), %eax
295	movl	4(%ecx), %edx
296	ret
297	END(dtrace_fuword64_nocheck)
298
299/*
300void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)
301*/
302
303	ENTRY(dtrace_probe_error)
304	pushl	%ebp
305	movl	%esp, %ebp
306	pushl	0x1c(%ebp)
307	pushl	0x18(%ebp)
308	pushl	0x14(%ebp)
309	pushl	0x10(%ebp)
310	pushl	0xc(%ebp)
311	pushl	0x8(%ebp)
312	pushl	dtrace_probeid_error
313	call	dtrace_probe
314	movl	%ebp, %esp
315	popl	%ebp
316	ret
317	END(dtrace_probe_error)
318
319/*
320void dtrace_membar_producer(void)
321*/
322
323	ENTRY(dtrace_membar_producer)
324	rep;	ret	/* use 2 byte return instruction when branch target */
325			/* AMD Software Optimization Guide - Section 6.2 */
326	END(dtrace_membar_producer)
327
328/*
329void dtrace_membar_consumer(void)
330*/
331
332	ENTRY(dtrace_membar_consumer)
333	rep;	ret	/* use 2 byte return instruction when branch target */
334			/* AMD Software Optimization Guide - Section 6.2 */
335	END(dtrace_membar_consumer)
336
337/*
338dtrace_icookie_t dtrace_interrupt_disable(void)
339*/
340	ENTRY(dtrace_interrupt_disable)
341	pushfl
342	popl	%eax
343	cli
344	ret
345	END(dtrace_interrupt_disable)
346
347/*
348void dtrace_interrupt_enable(dtrace_icookie_t cookie)
349*/
350	ENTRY(dtrace_interrupt_enable)
351	movl	4(%esp), %eax
352	pushl	%eax
353	popfl
354	ret
355	END(dtrace_interrupt_enable)
356