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