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