1179237Sjb/*
2179237Sjb * CDDL HEADER START
3179237Sjb *
4179237Sjb * The contents of this file are subject to the terms of the
5179237Sjb * Common Development and Distribution License, Version 1.0 only
6179237Sjb * (the "License").  You may not use this file except in compliance
7179237Sjb * with the License.
8179237Sjb *
9179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10179237Sjb * or http://www.opensolaris.org/os/licensing.
11179237Sjb * See the License for the specific language governing permissions
12179237Sjb * and limitations under the License.
13179237Sjb *
14179237Sjb * When distributing Covered Code, include this CDDL HEADER in each
15179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16179237Sjb * If applicable, add the following below this CDDL HEADER, with the
17179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying
18179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
19179237Sjb *
20179237Sjb * CDDL HEADER END
21179237Sjb *
22179237Sjb * $FreeBSD: releng/10.2/sys/cddl/dev/dtrace/i386/dtrace_asm.S 283676 2015-05-29 04:01:39Z markj $
23179237Sjb */
24179237Sjb/*
25179237Sjb * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26179237Sjb * Use is subject to license terms.
27179237Sjb */
28179237Sjb
29179237Sjb#define _ASM
30179237Sjb
31179237Sjb#include <machine/asmacros.h>
32179237Sjb#include <sys/cpuvar_defs.h>
33179237Sjb#include <sys/dtrace.h>
34179237Sjb
35179237Sjb#include "assym.s"
36179237Sjb
37179237Sjb	.globl	calltrap
38179237Sjb	.type	calltrap,@function
39179237Sjb	ENTRY(dtrace_invop_start)
40179237Sjb
41179237Sjb	pushl	%eax			/* push %eax -- may be return value */
42179237Sjb	pushl	%esp			/* push stack pointer */
43179237Sjb	addl	$48, (%esp)		/* adjust to incoming args */
44179237Sjb	pushl	40(%esp)		/* push calling EIP */
45179237Sjb
46179237Sjb	/*
47179237Sjb	 * Call dtrace_invop to let it check if the exception was
48179237Sjb	 * a fbt one. The return value in %eax will tell us what
49179237Sjb	 * dtrace_invop wants us to do.
50179237Sjb	 */
51179237Sjb	call	dtrace_invop
52269557Smarkj	ALTENTRY(dtrace_invop_callsite)
53179237Sjb	addl	$12, %esp
54179237Sjb	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
55179237Sjb	je	invop_push
56179237Sjb	cmpl	$DTRACE_INVOP_POPL_EBP, %eax
57179237Sjb	je	invop_pop
58179237Sjb	cmpl	$DTRACE_INVOP_LEAVE, %eax
59179237Sjb	je	invop_leave
60179237Sjb	cmpl	$DTRACE_INVOP_NOP, %eax
61179237Sjb	je	invop_nop
62179237Sjb
63179237Sjb	/* When all else fails handle the trap in the usual way. */
64179237Sjb	jmpl	*dtrace_invop_calltrap_addr
65179237Sjb
66179237Sjbinvop_push:
67179237Sjb	/*
68179237Sjb	 * We must emulate a "pushl %ebp".  To do this, we pull the stack
69179237Sjb	 * down 4 bytes, and then store the base pointer.
70179237Sjb	 */
71179237Sjb	popal
72179237Sjb	subl	$4, %esp		/* make room for %ebp */
73179237Sjb	pushl	%eax			/* push temp */
74179237Sjb	movl	8(%esp), %eax		/* load calling EIP */
75179237Sjb	incl	%eax			/* increment over LOCK prefix */
76179237Sjb	movl	%eax, 4(%esp)		/* store calling EIP */
77179237Sjb	movl	12(%esp), %eax		/* load calling CS */
78179237Sjb	movl	%eax, 8(%esp)		/* store calling CS */
79179237Sjb	movl	16(%esp), %eax		/* load calling EFLAGS */
80179237Sjb	movl	%eax, 12(%esp)		/* store calling EFLAGS */
81179237Sjb	movl	%ebp, 16(%esp)		/* push %ebp */
82179237Sjb	popl	%eax			/* pop off temp */
83179237Sjb	iret				/* Return from interrupt. */
84179237Sjbinvop_pop:
85179237Sjb	/*
86179237Sjb	 * We must emulate a "popl %ebp".  To do this, we do the opposite of
87179237Sjb	 * the above:  we remove the %ebp from the stack, and squeeze up the
88179237Sjb	 * saved state from the trap.
89179237Sjb	 */
90179237Sjb	popal
91179237Sjb	pushl	%eax			/* push temp */
92179237Sjb	movl	16(%esp), %ebp		/* pop %ebp */
93179237Sjb	movl	12(%esp), %eax		/* load calling EFLAGS */
94179237Sjb	movl	%eax, 16(%esp)		/* store calling EFLAGS */
95179237Sjb	movl	8(%esp), %eax		/* load calling CS */
96179237Sjb	movl	%eax, 12(%esp)		/* store calling CS */
97179237Sjb	movl	4(%esp), %eax		/* load calling EIP */
98179237Sjb	incl	%eax			/* increment over LOCK prefix */
99179237Sjb	movl	%eax, 8(%esp)		/* store calling EIP */
100179237Sjb	popl	%eax			/* pop off temp */
101179237Sjb	addl	$4, %esp		/* adjust stack pointer */
102179237Sjb	iret				/* Return from interrupt. */
103179237Sjbinvop_leave:
104179237Sjb	/*
105179237Sjb	 * We must emulate a "leave", which is the same as a "movl %ebp, %esp"
106179237Sjb	 * followed by a "popl %ebp".  This looks similar to the above, but
107179237Sjb	 * requires two temporaries:  one for the new base pointer, and one
108179237Sjb	 * for the staging register.
109179237Sjb	 */
110179237Sjb	popa
111179237Sjb	pushl	%eax			/* push temp */
112179237Sjb	pushl	%ebx			/* push temp */
113179237Sjb	movl	%ebp, %ebx		/* set temp to old %ebp */
114179237Sjb	movl	(%ebx), %ebp		/* pop %ebp */
115179237Sjb	movl	16(%esp), %eax		/* load calling EFLAGS */
116179237Sjb	movl	%eax, (%ebx)		/* store calling EFLAGS */
117179237Sjb	movl	12(%esp), %eax		/* load calling CS */
118179237Sjb	movl	%eax, -4(%ebx)		/* store calling CS */
119179237Sjb	movl	8(%esp), %eax		/* load calling EIP */
120179237Sjb	incl	%eax			/* increment over LOCK prefix */
121179237Sjb	movl	%eax, -8(%ebx)		/* store calling EIP */
122227430Srstone	subl	$8, %ebx		/* adjust for three pushes, one pop */
123227430Srstone	movl	%ebx, 8(%esp)		/* temporarily store new %esp */
124179237Sjb	popl	%ebx			/* pop off temp */
125179237Sjb	popl	%eax			/* pop off temp */
126227430Srstone	movl	(%esp), %esp		/* set stack pointer */
127179237Sjb	iret				/* return from interrupt */
128179237Sjbinvop_nop:
129179237Sjb	/*
130179237Sjb	 * We must emulate a "nop".  This is obviously not hard:  we need only
131179237Sjb	 * advance the %eip by one.
132179237Sjb	 */
133179237Sjb	popa
134179237Sjb	incl	(%esp)
135179237Sjb	iret				/* return from interrupt */
136179237Sjb
137179237Sjb	END(dtrace_invop_start)
138179237Sjb
139179237Sjb/*
140179237Sjbvoid dtrace_invop_init(void)
141179237Sjb*/
142179237Sjb	ENTRY(dtrace_invop_init)
143179237Sjb	movl	$dtrace_invop_start, dtrace_invop_jump_addr
144179237Sjb	ret
145179237Sjb	END(dtrace_invop_init)
146179237Sjb
147179237Sjb/*
148179237Sjbvoid dtrace_invop_uninit(void)
149179237Sjb*/
150179237Sjb	ENTRY(dtrace_invop_uninit)
151179237Sjb	movl	$0, dtrace_invop_jump_addr
152179237Sjb	ret
153179237Sjb	END(dtrace_invop_uninit)
154179237Sjb
155179237Sjb/*
156179237Sjbgreg_t dtrace_getfp(void)
157179237Sjb*/
158179237Sjb
159179237Sjb	ENTRY(dtrace_getfp)
160179237Sjb	movl	%ebp, %eax
161179237Sjb	ret
162179237Sjb	END(dtrace_getfp)
163179237Sjb
164179237Sjb/*
165179237Sjbuint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
166179237Sjb*/
167179237Sjb
168179237Sjb	ENTRY(dtrace_cas32)
169179237Sjb	ALTENTRY(dtrace_casptr)
170179237Sjb	movl	4(%esp), %edx
171179237Sjb	movl	8(%esp), %eax
172179237Sjb	movl	12(%esp), %ecx
173179237Sjb	lock
174179237Sjb	cmpxchgl %ecx, (%edx)
175179237Sjb	ret
176179237Sjb	END(dtrace_casptr)
177179237Sjb	END(dtrace_cas32)
178179237Sjb
179179237Sjb/*
180179237Sjbuintptr_t dtrace_caller(int aframes)
181179237Sjb*/
182179237Sjb
183179237Sjb	ENTRY(dtrace_caller)
184179237Sjb	movl	$-1, %eax
185179237Sjb	ret
186179237Sjb	END(dtrace_caller)
187179237Sjb
188179237Sjb/*
189179237Sjbvoid dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
190179237Sjb*/
191179237Sjb
192179237Sjb	ENTRY(dtrace_copy)
193179237Sjb	pushl	%ebp
194179237Sjb	movl	%esp, %ebp
195179237Sjb	pushl	%esi
196179237Sjb	pushl	%edi
197179237Sjb
198179237Sjb	movl	8(%ebp), %esi		/* Load source address */
199179237Sjb	movl	12(%ebp), %edi		/* Load destination address */
200179237Sjb	movl	16(%ebp), %ecx		/* Load count */
201179237Sjb	repz				/* Repeat for count... */
202179237Sjb	smovb				/*   move from %ds:si to %es:di */
203179237Sjb
204179237Sjb	popl	%edi
205179237Sjb	popl	%esi
206179237Sjb	movl	%ebp, %esp
207179237Sjb	popl	%ebp
208179237Sjb	ret
209179237Sjb	END(dtrace_copy)
210179237Sjb
211179237Sjb/*
212179237Sjbvoid dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size)
213179237Sjb*/
214179237Sjb
215179237Sjb	ENTRY(dtrace_copystr)
216179237Sjb
217179237Sjb	pushl	%ebp			/* Setup stack frame */
218179237Sjb	movl	%esp, %ebp
219179237Sjb	pushl	%ebx			/* Save registers */
220179237Sjb
221179237Sjb	movl	8(%ebp), %ebx		/* Load source address */
222179237Sjb	movl	12(%ebp), %edx		/* Load destination address */
223179237Sjb	movl	16(%ebp), %ecx		/* Load count */
224179237Sjb
225179237Sjb0:
226179237Sjb	movb	(%ebx), %al		/* Load from source */
227179237Sjb	movb	%al, (%edx)		/* Store to destination */
228179237Sjb	incl	%ebx			/* Increment source pointer */
229179237Sjb	incl	%edx			/* Increment destination pointer */
230179237Sjb	decl	%ecx			/* Decrement remaining count */
231179237Sjb	cmpb	$0, %al
232179237Sjb	je	1f
233179237Sjb	cmpl	$0, %ecx
234179237Sjb	jne	0b
235179237Sjb
236179237Sjb1:
237179237Sjb	popl	%ebx
238179237Sjb	movl	%ebp, %esp
239179237Sjb	popl	%ebp
240179237Sjb	ret
241179237Sjb
242179237Sjb	END(dtrace_copystr)
243179237Sjb
244179237Sjb/*
245179237Sjbuintptr_t dtrace_fulword(void *addr)
246179237Sjb*/
247179237Sjb
248179237Sjb	ENTRY(dtrace_fulword)
249179237Sjb	movl	4(%esp), %ecx
250179237Sjb	xorl	%eax, %eax
251179237Sjb	movl	(%ecx), %eax
252179237Sjb	ret
253179237Sjb	END(dtrace_fulword)
254179237Sjb
255179237Sjb/*
256179237Sjbuint8_t dtrace_fuword8_nocheck(void *addr)
257179237Sjb*/
258179237Sjb
259179237Sjb	ENTRY(dtrace_fuword8_nocheck)
260179237Sjb	movl	4(%esp), %ecx
261179237Sjb	xorl	%eax, %eax
262179237Sjb	movzbl	(%ecx), %eax
263179237Sjb	ret
264179237Sjb	END(dtrace_fuword8_nocheck)
265179237Sjb
266179237Sjb/*
267179237Sjbuint16_t dtrace_fuword16_nocheck(void *addr)
268179237Sjb*/
269179237Sjb
270179237Sjb	ENTRY(dtrace_fuword16_nocheck)
271179237Sjb	movl	4(%esp), %ecx
272179237Sjb	xorl	%eax, %eax
273179237Sjb	movzwl	(%ecx), %eax
274179237Sjb	ret
275179237Sjb	END(dtrace_fuword16_nocheck)
276179237Sjb
277179237Sjb/*
278179237Sjbuint32_t dtrace_fuword32_nocheck(void *addr)
279179237Sjb*/
280179237Sjb
281179237Sjb	ENTRY(dtrace_fuword32_nocheck)
282179237Sjb	movl	4(%esp), %ecx
283179237Sjb	xorl	%eax, %eax
284179237Sjb	movl	(%ecx), %eax
285179237Sjb	ret
286179237Sjb	END(dtrace_fuword32_nocheck)
287179237Sjb
288179237Sjb/*
289179237Sjbuint64_t dtrace_fuword64_nocheck(void *addr)
290179237Sjb*/
291179237Sjb
292179237Sjb	ENTRY(dtrace_fuword64_nocheck)
293179237Sjb	movl	4(%esp), %ecx
294179237Sjb	xorl	%eax, %eax
295179237Sjb	xorl	%edx, %edx
296179237Sjb	movl	(%ecx), %eax
297179237Sjb	movl	4(%ecx), %edx
298179237Sjb	ret
299179237Sjb	END(dtrace_fuword64_nocheck)
300179237Sjb
301179237Sjb/*
302179237Sjbvoid dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)
303179237Sjb*/
304179237Sjb
305179237Sjb	ENTRY(dtrace_probe_error)
306179237Sjb	pushl	%ebp
307179237Sjb	movl	%esp, %ebp
308179237Sjb	pushl	0x1c(%ebp)
309179237Sjb	pushl	0x18(%ebp)
310179237Sjb	pushl	0x14(%ebp)
311179237Sjb	pushl	0x10(%ebp)
312179237Sjb	pushl	0xc(%ebp)
313179237Sjb	pushl	0x8(%ebp)
314179237Sjb	pushl	dtrace_probeid_error
315179237Sjb	call	dtrace_probe
316179237Sjb	movl	%ebp, %esp
317179237Sjb	popl	%ebp
318179237Sjb	ret
319179237Sjb	END(dtrace_probe_error)
320179237Sjb
321179237Sjb/*
322179237Sjbvoid dtrace_membar_producer(void)
323179237Sjb*/
324179237Sjb
325179237Sjb	ENTRY(dtrace_membar_producer)
326179237Sjb	rep;	ret	/* use 2 byte return instruction when branch target */
327179237Sjb			/* AMD Software Optimization Guide - Section 6.2 */
328179237Sjb	END(dtrace_membar_producer)
329179237Sjb
330179237Sjb/*
331179237Sjbvoid dtrace_membar_consumer(void)
332179237Sjb*/
333179237Sjb
334179237Sjb	ENTRY(dtrace_membar_consumer)
335179237Sjb	rep;	ret	/* use 2 byte return instruction when branch target */
336179237Sjb			/* AMD Software Optimization Guide - Section 6.2 */
337179237Sjb	END(dtrace_membar_consumer)
338179237Sjb
339179237Sjb/*
340179237Sjbdtrace_icookie_t dtrace_interrupt_disable(void)
341179237Sjb*/
342179237Sjb	ENTRY(dtrace_interrupt_disable)
343179237Sjb	pushfl
344179237Sjb	popl	%eax
345179237Sjb	cli
346179237Sjb	ret
347179237Sjb	END(dtrace_interrupt_disable)
348179237Sjb
349179237Sjb/*
350179237Sjbvoid dtrace_interrupt_enable(dtrace_icookie_t cookie)
351179237Sjb*/
352179237Sjb	ENTRY(dtrace_interrupt_enable)
353179237Sjb	movl	4(%esp), %eax
354179237Sjb	pushl	%eax
355179237Sjb	popfl
356179237Sjb	ret
357179237Sjb	END(dtrace_interrupt_enable)
358