1164190Sjkoshy/*	$NetBSD: dtrace_asm.S,v 1.8 2023/11/03 09:07:57 chs Exp $	*/
2164190Sjkoshy
3164190Sjkoshy/*
4164190Sjkoshy * CDDL HEADER START
5164190Sjkoshy *
6164190Sjkoshy * The contents of this file are subject to the terms of the
7164190Sjkoshy * Common Development and Distribution License, Version 1.0 only
8164190Sjkoshy * (the "License").  You may not use this file except in compliance
9164190Sjkoshy * with the License.
10164190Sjkoshy *
11164190Sjkoshy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12164190Sjkoshy * or http://www.opensolaris.org/os/licensing.
13164190Sjkoshy * See the License for the specific language governing permissions
14164190Sjkoshy * and limitations under the License.
15164190Sjkoshy *
16164190Sjkoshy * When distributing Covered Code, include this CDDL HEADER in each
17164190Sjkoshy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18164190Sjkoshy * If applicable, add the following below this CDDL HEADER, with the
19164190Sjkoshy * fields enclosed by brackets "[]" replaced with your own identifying
20164190Sjkoshy * information: Portions Copyright [yyyy] [name of copyright owner]
21164190Sjkoshy *
22164190Sjkoshy * CDDL HEADER END
23164190Sjkoshy *
24164190Sjkoshy * $FreeBSD: head/sys/cddl/dev/dtrace/i386/dtrace_asm.S 298171 2016-04-17 23:08:47Z markj $
25164190Sjkoshy */
26164190Sjkoshy/*
27164190Sjkoshy * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28164190Sjkoshy * Use is subject to license terms.
29164190Sjkoshy */
30164190Sjkoshy
31164190Sjkoshy#define _ASM
32164190Sjkoshy
33164190Sjkoshy#include "assym.h"
34164190Sjkoshy
35164190Sjkoshy#include <sys/cpuvar_defs.h>
36164190Sjkoshy#include <sys/dtrace.h>
37164190Sjkoshy#include <machine/asm.h>
38164190Sjkoshy#include <machine/frameasm.h>
39164190Sjkoshy#include <machine/trap.h>
40164190Sjkoshy
41164190Sjkoshy#define DTRACE_SMAP_DISABLE			\
42164190Sjkoshy	call	dtrace_smap_disable
43164190Sjkoshy#define DTRACE_SMAP_ENABLE			\
44164190Sjkoshy	call	dtrace_smap_enable
45164190Sjkoshy
46164190Sjkoshy#define INTR_POP		\
47164190Sjkoshy	addl	$16, %esp;	\
48164190Sjkoshy	popl	%edi;		\
49164190Sjkoshy	popl	%esi;		\
50164190Sjkoshy	popl	%ebp;		\
51164190Sjkoshy	popl	%ebx;		\
52164190Sjkoshy	popl	%edx;		\
53164190Sjkoshy	popl	%ecx;		\
54164190Sjkoshy	popl	%eax;		\
55164190Sjkoshy	addl	$8, %esp
56164190Sjkoshy
57164190Sjkoshy	ENTRY(dtrace_invop_start)
58164190Sjkoshy
59164190Sjkoshy	/* Store a trapframe for dtrace. */
60164190Sjkoshy	pushl	$0
61164190Sjkoshy	pushl	$T_PRIVINFLT
62164190Sjkoshy	pushl	%eax
63164190Sjkoshy	pushl	%ecx
64164190Sjkoshy	pushl	%edx
65165316Sjkoshy	pushl	%ebx
66164190Sjkoshy	pushl	%ebp
67164190Sjkoshy	pushl	%esi
68164190Sjkoshy	pushl	%edi
69164190Sjkoshy	subl	$16,%esp		/* dummy for segment regs */
70164190Sjkoshy	cld
71165316Sjkoshy
72164190Sjkoshy	/* Store the args to dtrace_invop(). */
73164190Sjkoshy	pushl	%eax			/* push %eax -- may be return value */
74164190Sjkoshy	pushl	%esp			/* push stack pointer */
75164190Sjkoshy	addl	$4, (%esp)		/* skip first arg and segment regs */
76165316Sjkoshy	pushl	TF_EIP+8(%esp)		/* push calling EIP */
77164190Sjkoshy
78164190Sjkoshy	/*
79164190Sjkoshy	 * Call dtrace_invop to let it check if the exception was
80164190Sjkoshy	 * a fbt one. The return value in %eax will tell us what
81164190Sjkoshy	 * dtrace_invop wants us to do.
82164190Sjkoshy	 */
83164190Sjkoshy	call	dtrace_invop
84164190Sjkoshy	ALTENTRY(dtrace_invop_callsite)
85164190Sjkoshy	addl	$12, %esp
86164190Sjkoshy	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
87165316Sjkoshy	je	invop_push
88164190Sjkoshy	cmpl	$DTRACE_INVOP_POPL_EBP, %eax
89164190Sjkoshy	je	invop_pop
90164190Sjkoshy	cmpl	$DTRACE_INVOP_LEAVE, %eax
91164190Sjkoshy	je	invop_leave
92164190Sjkoshy	cmpl	$DTRACE_INVOP_NOP, %eax
93164190Sjkoshy	je	invop_nop
94164190Sjkoshy
95164190Sjkoshy	/* When all else fails handle the trap in the usual way. */
96164190Sjkoshy	jmpl	*dtrace_invop_calltrap_addr
97164190Sjkoshy
98164190Sjkoshyinvop_push:
99164190Sjkoshy	/*
100164190Sjkoshy	 * We must emulate a "pushl %ebp".  To do this, we pull the stack
101164190Sjkoshy	 * down 4 bytes, and then store the base pointer.
102164190Sjkoshy	 */
103164190Sjkoshy	INTR_POP
104164190Sjkoshy	subl	$4, %esp		/* make room for %ebp */
105164190Sjkoshy	pushl	%eax			/* push temp */
106164190Sjkoshy	movl	8(%esp), %eax		/* load calling EIP */
107164190Sjkoshy	incl	%eax			/* increment over LOCK prefix */
108164190Sjkoshy	movl	%eax, 4(%esp)		/* store calling EIP */
109164190Sjkoshy	movl	12(%esp), %eax		/* load calling CS */
110164190Sjkoshy	movl	%eax, 8(%esp)		/* store calling CS */
111164190Sjkoshy	movl	16(%esp), %eax		/* load calling EFLAGS */
112164190Sjkoshy	movl	%eax, 12(%esp)		/* store calling EFLAGS */
113165316Sjkoshy	movl	%ebp, 16(%esp)		/* push %ebp */
114164190Sjkoshy	popl	%eax			/* pop off temp */
115164190Sjkoshy	iret				/* Return from interrupt. */
116164190Sjkoshyinvop_pop:
117164190Sjkoshy	/*
118164190Sjkoshy	 * We must emulate a "popl %ebp".  To do this, we do the opposite of
119165316Sjkoshy	 * the above:  we remove the %ebp from the stack, and squeeze up the
120164190Sjkoshy	 * saved state from the trap.
121164190Sjkoshy	 */
122164190Sjkoshy	INTR_POP
123164190Sjkoshy	pushl	%eax			/* push temp */
124165316Sjkoshy	movl	16(%esp), %ebp		/* pop %ebp */
125164190Sjkoshy	movl	12(%esp), %eax		/* load calling EFLAGS */
126164190Sjkoshy	movl	%eax, 16(%esp)		/* store calling EFLAGS */
127164190Sjkoshy	movl	8(%esp), %eax		/* load calling CS */
128164190Sjkoshy	movl	%eax, 12(%esp)		/* store calling CS */
129164190Sjkoshy	movl	4(%esp), %eax		/* load calling EIP */
130164190Sjkoshy	incl	%eax			/* increment over LOCK prefix */
131164190Sjkoshy	movl	%eax, 8(%esp)		/* store calling EIP */
132164190Sjkoshy	popl	%eax			/* pop off temp */
133164190Sjkoshy	addl	$4, %esp		/* adjust stack pointer */
134164190Sjkoshy	iret				/* Return from interrupt. */
135165316Sjkoshyinvop_leave:
136164190Sjkoshy	/*
137164190Sjkoshy	 * We must emulate a "leave", which is the same as a "movl %ebp, %esp"
138164190Sjkoshy	 * followed by a "popl %ebp".  This looks similar to the above, but
139164190Sjkoshy	 * requires two temporaries:  one for the new base pointer, and one
140164190Sjkoshy	 * for the staging register.
141164190Sjkoshy	 */
142164190Sjkoshy	INTR_POP
143164190Sjkoshy	pushl	%eax			/* push temp */
144164190Sjkoshy	pushl	%ebx			/* push temp */
145164190Sjkoshy	movl	%ebp, %ebx		/* set temp to old %ebp */
146164190Sjkoshy	movl	(%ebx), %ebp		/* pop %ebp */
147164190Sjkoshy	movl	16(%esp), %eax		/* load calling EFLAGS */
148164190Sjkoshy	movl	%eax, (%ebx)		/* store calling EFLAGS */
149164190Sjkoshy	movl	12(%esp), %eax		/* load calling CS */
150164190Sjkoshy	movl	%eax, -4(%ebx)		/* store calling CS */
151164190Sjkoshy	movl	8(%esp), %eax		/* load calling EIP */
152164190Sjkoshy	incl	%eax			/* increment over LOCK prefix */
153164190Sjkoshy	movl	%eax, -8(%ebx)		/* store calling EIP */
154164190Sjkoshy	subl	$8, %ebx		/* adjust for three pushes, one pop */
155	movl	%ebx, 8(%esp)		/* temporarily store new %esp */
156	popl	%ebx			/* pop off temp */
157	popl	%eax			/* pop off temp */
158	movl	(%esp), %esp		/* set stack pointer */
159	iret				/* return from interrupt */
160invop_nop:
161	/*
162	 * We must emulate a "nop".  This is obviously not hard:  we need only
163	 * advance the %eip by one.
164	 */
165	INTR_POP
166	incl	(%esp)
167	iret				/* return from interrupt */
168
169	END(dtrace_invop_start)
170
171/*
172void dtrace_invop_init(void)
173*/
174	ENTRY(dtrace_invop_init)
175	movl	$dtrace_invop_start, dtrace_invop_jump_addr
176	ret
177	END(dtrace_invop_init)
178
179/*
180void dtrace_invop_uninit(void)
181*/
182	ENTRY(dtrace_invop_uninit)
183	movl	$0, dtrace_invop_jump_addr
184	ret
185	END(dtrace_invop_uninit)
186
187/*
188greg_t dtrace_getfp(void)
189*/
190
191	ENTRY(dtrace_getfp)
192	movl	%ebp, %eax
193	ret
194	END(dtrace_getfp)
195
196/*
197uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
198*/
199
200	ENTRY(dtrace_cas32)
201	ALTENTRY(dtrace_casptr)
202	movl	4(%esp), %edx
203	movl	8(%esp), %eax
204	movl	12(%esp), %ecx
205	lock
206	cmpxchgl %ecx, (%edx)
207	ret
208	END(dtrace_casptr)
209	END(dtrace_cas32)
210
211/*
212uintptr_t dtrace_caller(int aframes)
213*/
214
215	ENTRY(dtrace_caller)
216	movl	$-1, %eax
217	ret
218	END(dtrace_caller)
219
220/*
221void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
222*/
223
224	ENTRY(dtrace_copy)
225	pushl	%ebp
226	movl	%esp, %ebp
227	pushl	%esi
228	pushl	%edi
229
230	movl	8(%ebp), %esi		/* Load source address */
231	movl	12(%ebp), %edi		/* Load destination address */
232	movl	16(%ebp), %ecx		/* Load count */
233	DTRACE_SMAP_DISABLE
234	repz				/* Repeat for count... */
235	smovb				/*   move from %ds:si to %es:di */
236	DTRACE_SMAP_ENABLE
237
238	popl	%edi
239	popl	%esi
240	movl	%ebp, %esp
241	popl	%ebp
242	ret
243	END(dtrace_copy)
244
245/*
246void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size)
247*/
248
249	ENTRY(dtrace_copystr)
250
251	pushl	%ebp			/* Setup stack frame */
252	movl	%esp, %ebp
253	pushl	%ebx			/* Save registers */
254
255	movl	8(%ebp), %ebx		/* Load source address */
256	movl	12(%ebp), %edx		/* Load destination address */
257	movl	16(%ebp), %ecx		/* Load count */
258	DTRACE_SMAP_DISABLE
259
2600:
261	movb	(%ebx), %al		/* Load from source */
262	movb	%al, (%edx)		/* Store to destination */
263	incl	%ebx			/* Increment source pointer */
264	incl	%edx			/* Increment destination pointer */
265	decl	%ecx			/* Decrement remaining count */
266	cmpb	$0, %al
267	je	1f
268	cmpl	$0, %ecx
269	jne	0b
270
2711:
272	DTRACE_SMAP_ENABLE
273	popl	%ebx
274	movl	%ebp, %esp
275	popl	%ebp
276	ret
277
278	END(dtrace_copystr)
279
280/*
281uintptr_t dtrace_fulword(void *addr)
282*/
283
284	ENTRY(dtrace_fulword)
285	movl	4(%esp), %ecx
286	xorl	%eax, %eax
287	DTRACE_SMAP_DISABLE
288	movl	(%ecx), %eax
289	DTRACE_SMAP_ENABLE
290	ret
291	END(dtrace_fulword)
292
293/*
294uint8_t dtrace_fuword8_nocheck(void *addr)
295*/
296
297	ENTRY(dtrace_fuword8_nocheck)
298	movl	4(%esp), %ecx
299	xorl	%eax, %eax
300	DTRACE_SMAP_DISABLE
301	movzbl	(%ecx), %eax
302	DTRACE_SMAP_ENABLE
303	ret
304	END(dtrace_fuword8_nocheck)
305
306/*
307uint16_t dtrace_fuword16_nocheck(void *addr)
308*/
309
310	ENTRY(dtrace_fuword16_nocheck)
311	movl	4(%esp), %ecx
312	xorl	%eax, %eax
313	DTRACE_SMAP_DISABLE
314	movzwl	(%ecx), %eax
315	DTRACE_SMAP_ENABLE
316	ret
317	END(dtrace_fuword16_nocheck)
318
319/*
320uint32_t dtrace_fuword32_nocheck(void *addr)
321*/
322
323	ENTRY(dtrace_fuword32_nocheck)
324	movl	4(%esp), %ecx
325	xorl	%eax, %eax
326	DTRACE_SMAP_DISABLE
327	movl	(%ecx), %eax
328	DTRACE_SMAP_ENABLE
329	ret
330	END(dtrace_fuword32_nocheck)
331
332/*
333uint64_t dtrace_fuword64_nocheck(void *addr)
334*/
335
336	ENTRY(dtrace_fuword64_nocheck)
337	movl	4(%esp), %ecx
338	xorl	%eax, %eax
339	xorl	%edx, %edx
340	DTRACE_SMAP_DISABLE
341	movl	(%ecx), %eax
342	movl	4(%ecx), %edx
343	DTRACE_SMAP_ENABLE
344	ret
345	END(dtrace_fuword64_nocheck)
346
347/*
348void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)
349*/
350
351	ENTRY(dtrace_probe_error)
352	pushl	%ebp
353	movl	%esp, %ebp
354	pushl	0x1c(%ebp)
355	pushl	0x18(%ebp)
356	pushl	0x14(%ebp)
357	pushl	0x10(%ebp)
358	pushl	0xc(%ebp)
359	pushl	0x8(%ebp)
360	pushl	dtrace_probeid_error
361	call	dtrace_probe
362	movl	%ebp, %esp
363	popl	%ebp
364	ret
365	END(dtrace_probe_error)
366
367/*
368void dtrace_membar_producer(void)
369*/
370
371	ENTRY(dtrace_membar_producer)
372	rep;	ret	/* use 2 byte return instruction when branch target */
373			/* AMD Software Optimization Guide - Section 6.2 */
374	END(dtrace_membar_producer)
375
376/*
377void dtrace_membar_consumer(void)
378*/
379
380	ENTRY(dtrace_membar_consumer)
381	rep;	ret	/* use 2 byte return instruction when branch target */
382			/* AMD Software Optimization Guide - Section 6.2 */
383	END(dtrace_membar_consumer)
384
385/*
386dtrace_icookie_t dtrace_interrupt_disable(void)
387*/
388	ENTRY(dtrace_interrupt_disable)
389	pushfl
390	popl	%eax
391	cli
392	ret
393	END(dtrace_interrupt_disable)
394
395/*
396void dtrace_interrupt_enable(dtrace_icookie_t cookie)
397*/
398	ENTRY(dtrace_interrupt_enable)
399	movl	4(%esp), %eax
400	pushl	%eax
401	popfl
402	ret
403	END(dtrace_interrupt_enable)
404