dtrace_asm.S revision 1.5
1/*	$NetBSD: dtrace_asm.S,v 1.5 2015/05/18 14:41:41 christos 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 (the "License").
8 * You may not use this file except in compliance with the License.
9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 *
23 * Portions Copyright 2008 John Birrell <jb@freebsd.org>
24 *
25 * $FreeBSD: src/sys/cddl/dev/dtrace/amd64/dtrace_asm.S,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $
26 *
27 */
28/*
29 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
30 * Use is subject to license terms.
31 */
32
33#define _ASM
34
35#include <sys/cpuvar_defs.h>
36#include <sys/dtrace.h>
37#include <machine/asm.h>
38#define MEXITCOUNT
39
40#include "assym.h"
41
42#define INTR_POP				\
43	MEXITCOUNT;				\
44	movq	TF_RDI(%rsp),%rdi;		\
45	movq	TF_RSI(%rsp),%rsi;		\
46	movq	TF_RDX(%rsp),%rdx;		\
47	movq	TF_RCX(%rsp),%rcx;		\
48	movq	TF_R8(%rsp),%r8;		\
49	movq	TF_R9(%rsp),%r9;		\
50	movq	TF_RAX(%rsp),%rax;		\
51	movq	TF_RBX(%rsp),%rbx;		\
52	movq	TF_RBP(%rsp),%rbp;		\
53	movq	TF_R10(%rsp),%r10;		\
54	movq	TF_R11(%rsp),%r11;		\
55	movq	TF_R12(%rsp),%r12;		\
56	movq	TF_R13(%rsp),%r13;		\
57	movq	TF_R14(%rsp),%r14;		\
58	movq	TF_R15(%rsp),%r15;		\
59	testb	$SEL_RPL_MASK,TF_CS(%rsp);	\
60	jz	1f;				\
61	cli;					\
62	swapgs;					\
631:	addq	$TF_RIP,%rsp;
64
65
66	ENTRY(dtrace_invop_start)
67
68	/*
69	 * #BP traps with %rip set to the next address. We need to decrement
70	 * the value to indicate the address of the int3 (0xcc) instruction
71	 * that we substituted.
72	 */
73	movq	TF_RIP(%rsp), %rdi
74	decq	%rdi
75	movq	TF_RSP(%rsp), %rsi
76	movq	TF_RAX(%rsp), %rdx
77	pushq	(%rsi)
78	movq	%rsp, %rsi
79	call	dtrace_invop
80	ALTENTRY(dtrace_invop_callsite)
81	addq	$8, %rsp
82	cmpl	$DTRACE_INVOP_PUSHL_EBP, %eax
83	je	bp_push
84	cmpl	$DTRACE_INVOP_LEAVE, %eax
85	je	bp_leave
86	cmpl	$DTRACE_INVOP_NOP, %eax
87	je	bp_nop
88	cmpl	$DTRACE_INVOP_RET, %eax
89	je	bp_ret
90
91	/* When all else fails handle the trap in the usual way. */
92	jmpq	*dtrace_invop_calltrap_addr
93
94bp_push:
95	/*
96	 * We must emulate a "pushq %rbp".  To do this, we pull the stack
97	 * down 8 bytes, and then store the base pointer.
98	 */
99	INTR_POP
100	subq	$16, %rsp		/* make room for %rbp */
101	pushq	%rax			/* push temp */
102	movq	24(%rsp), %rax		/* load calling RIP */
103	movq	%rax, 8(%rsp)		/* store calling RIP */
104	movq	32(%rsp), %rax		/* load calling CS */
105	movq	%rax, 16(%rsp)		/* store calling CS */
106	movq	40(%rsp), %rax		/* load calling RFLAGS */
107	movq	%rax, 24(%rsp)		/* store calling RFLAGS */
108	movq	48(%rsp), %rax		/* load calling RSP */
109	subq	$8, %rax		/* make room for %rbp */
110	movq	%rax, 32(%rsp)		/* store calling RSP */
111	movq	56(%rsp), %rax		/* load calling SS */
112	movq	%rax, 40(%rsp)		/* store calling SS */
113	movq	32(%rsp), %rax		/* reload calling RSP */
114	movq	%rbp, (%rax)		/* store %rbp there */
115	popq	%rax			/* pop off temp */
116	iretq				/* return from interrupt */
117	/*NOTREACHED*/
118
119bp_leave:
120	/*
121	 * We must emulate a "leave", which is the same as a "movq %rbp, %rsp"
122	 * followed by a "popq %rbp".  This is quite a bit simpler on amd64
123	 * than it is on i386 -- we can exploit the fact that the %rsp is
124	 * explicitly saved to effect the pop without having to reshuffle
125	 * the other data pushed for the trap.
126	 */
127	INTR_POP
128	pushq	%rax			/* push temp */
129	movq	8(%rsp), %rax		/* load calling RIP */
130	movq	%rax, 8(%rsp)		/* store calling RIP */
131	movq	(%rbp), %rax		/* get new %rbp */
132	addq	$8, %rbp		/* adjust new %rsp */
133	movq	%rbp, 32(%rsp)		/* store new %rsp */
134	movq	%rax, %rbp		/* set new %rbp */
135	popq	%rax			/* pop off temp */
136	iretq				/* return from interrupt */
137	/*NOTREACHED*/
138
139bp_nop:
140	/* We must emulate a "nop". */
141	INTR_POP
142	iretq
143	/*NOTREACHED*/
144
145bp_ret:
146	INTR_POP
147	pushq	%rax			/* push temp */
148	movq	32(%rsp), %rax		/* load %rsp */
149	movq	(%rax), %rax		/* load calling RIP */
150	movq	%rax, 8(%rsp)		/* store calling RIP */
151	addq	$8, 32(%rsp)		/* adjust new %rsp */
152	popq	%rax			/* pop off temp */
153	iretq				/* return from interrupt */
154	/*NOTREACHED*/
155
156	END(dtrace_invop_start)
157
158/*
159void dtrace_invop_init(void)
160*/
161	ENTRY(dtrace_invop_init)
162	movq	$dtrace_invop_start, dtrace_invop_jump_addr(%rip)
163	ret
164	END(dtrace_invop_init)
165
166/*
167void dtrace_invop_uninit(void)
168*/
169	ENTRY(dtrace_invop_uninit)
170	movq	$0, dtrace_invop_jump_addr(%rip)
171	ret
172	END(dtrace_invop_uninit)
173
174/*
175greg_t dtrace_getfp(void)
176*/
177	ENTRY(dtrace_getfp)
178	movq	%rbp, %rax
179	ret
180	END(dtrace_getfp)
181
182/*
183uint32_t
184dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
185*/
186	ENTRY(dtrace_cas32)
187	movl	%esi, %eax
188	lock
189	cmpxchgl %edx, (%rdi)
190	ret
191	END(dtrace_cas32)
192
193/*
194void *
195dtrace_casptr(void *target, void *cmp, void *new)
196*/
197	ENTRY(dtrace_casptr)
198	movq	%rsi, %rax
199	lock
200	cmpxchgq %rdx, (%rdi)
201	ret
202	END(dtrace_casptr)
203
204/*
205uintptr_t
206dtrace_caller(int aframes)
207*/
208	ENTRY(dtrace_caller)
209	movq	$-1, %rax
210	ret
211	END(dtrace_caller)
212
213/*
214void
215dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
216*/
217	ENTRY(dtrace_copy)
218	pushq	%rbp
219	movq	%rsp, %rbp
220
221	xchgq	%rdi, %rsi		/* make %rsi source, %rdi dest */
222	movq	%rdx, %rcx		/* load count */
223	repz				/* repeat for count ... */
224	smovb				/*   move from %ds:rsi to %ed:rdi */
225	leave
226	ret
227	END(dtrace_copy)
228
229/*
230void
231dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size,
232    volatile uint16_t *flags)
233*/
234	ENTRY(dtrace_copystr)
235	pushq	%rbp
236	movq	%rsp, %rbp
237
2380:
239	movb	(%rdi), %al		/* load from source */
240	movb	%al, (%rsi)		/* store to destination */
241	addq	$1, %rdi		/* increment source pointer */
242	addq	$1, %rsi		/* increment destination pointer */
243	subq	$1, %rdx		/* decrement remaining count */
244	cmpb	$0, %al
245	je	2f
246	testq	$0xfff, %rdx		/* test if count is 4k-aligned */
247	jnz	1f			/* if not, continue with copying */
248	testq	$CPU_DTRACE_BADADDR, (%rcx) /* load and test dtrace flags */
249	jnz	2f
2501:
251	cmpq	$0, %rdx
252	jne	0b
2532:
254	leave
255	ret
256
257	END(dtrace_copystr)
258
259/*
260uintptr_t
261dtrace_fulword(void *addr)
262*/
263	ENTRY(dtrace_fulword)
264	movq	(%rdi), %rax
265	ret
266	END(dtrace_fulword)
267
268/*
269uint8_t
270dtrace_fuword8_nocheck(void *addr)
271*/
272	ENTRY(dtrace_fuword8_nocheck)
273	xorq	%rax, %rax
274	movb	(%rdi), %al
275	ret
276	END(dtrace_fuword8_nocheck)
277
278/*
279uint16_t
280dtrace_fuword16_nocheck(void *addr)
281*/
282	ENTRY(dtrace_fuword16_nocheck)
283	xorq	%rax, %rax
284	movw	(%rdi), %ax
285	ret
286	END(dtrace_fuword16_nocheck)
287
288/*
289uint32_t
290dtrace_fuword32_nocheck(void *addr)
291*/
292	ENTRY(dtrace_fuword32_nocheck)
293	xorq	%rax, %rax
294	movl	(%rdi), %eax
295	ret
296	END(dtrace_fuword32_nocheck)
297
298/*
299uint64_t
300dtrace_fuword64_nocheck(void *addr)
301*/
302	ENTRY(dtrace_fuword64_nocheck)
303	movq	(%rdi), %rax
304	ret
305	END(dtrace_fuword64_nocheck)
306
307/*
308void
309dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which,
310    int fault, int fltoffs, uintptr_t illval)
311*/
312	ENTRY(dtrace_probe_error)
313	pushq	%rbp
314	movq	%rsp, %rbp
315	subq	$0x8, %rsp
316	movq	%r9, (%rsp)
317	movq	%r8, %r9
318	movq	%rcx, %r8
319	movq	%rdx, %rcx
320	movq	%rsi, %rdx
321	movq	%rdi, %rsi
322	movl	dtrace_probeid_error(%rip), %edi
323	call	dtrace_probe
324	addq	$0x8, %rsp
325	leave
326	ret
327	END(dtrace_probe_error)
328
329/*
330void
331dtrace_membar_producer(void)
332*/
333	ENTRY(dtrace_membar_producer)
334	rep;	ret	/* use 2 byte return instruction when branch target */
335			/* AMD Software Optimization Guide - Section 6.2 */
336	END(dtrace_membar_producer)
337
338/*
339void
340dtrace_membar_consumer(void)
341*/
342	ENTRY(dtrace_membar_consumer)
343	rep;	ret	/* use 2 byte return instruction when branch target */
344			/* AMD Software Optimization Guide - Section 6.2 */
345	END(dtrace_membar_consumer)
346
347/*
348dtrace_icookie_t
349dtrace_interrupt_disable(void)
350*/
351	ENTRY(dtrace_interrupt_disable)
352	pushfq
353	popq	%rax
354	cli
355	ret
356	END(dtrace_interrupt_disable)
357
358/*
359void
360dtrace_interrupt_enable(dtrace_icookie_t cookie)
361*/
362	ENTRY(dtrace_interrupt_enable)
363	pushq	%rdi
364	popfq
365	ret
366	END(dtrace_interrupt_enable)
367
368/*
369 * The panic() and cmn_err() functions invoke vpanic() as a common entry point
370 * into the panic code implemented in panicsys().  vpanic() is responsible
371 * for passing through the format string and arguments, and constructing a
372 * regs structure on the stack into which it saves the current register
373 * values.  If we are not dying due to a fatal trap, these registers will
374 * then be preserved in panicbuf as the current processor state.  Before
375 * invoking panicsys(), vpanic() activates the first panic trigger (see
376 * common/os/panic.c) and switches to the panic_stack if successful.  Note that
377 * DTrace takes a slightly different panic path if it must panic from probe
378 * context.  Instead of calling panic, it calls into dtrace_vpanic(), which
379 * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
380 * branches back into vpanic().
381 */
382
383/*
384void
385vpanic(const char *format, va_list alist)
386*/
387	ENTRY(vpanic)				/* Initial stack layout: */
388
389	pushq	%rbp				/* | %rip | 	0x60	*/
390	movq	%rsp, %rbp			/* | %rbp |	0x58	*/
391	pushfq					/* | rfl  |	0x50	*/
392	pushq	%r11				/* | %r11 |	0x48	*/
393	pushq	%r10				/* | %r10 |	0x40	*/
394	pushq	%rbx				/* | %rbx |	0x38	*/
395	pushq	%rax				/* | %rax |	0x30	*/
396	pushq	%r9				/* | %r9  |	0x28	*/
397	pushq	%r8				/* | %r8  |	0x20	*/
398	pushq	%rcx				/* | %rcx |	0x18	*/
399	pushq	%rdx				/* | %rdx |	0x10	*/
400	pushq	%rsi				/* | %rsi |	0x8 alist */
401	pushq	%rdi				/* | %rdi |	0x0 format */
402
403	movq	%rsp, %rbx			/* %rbx = current %rsp */
404
405	leaq	panic_quiesce(%rip), %rdi	/* %rdi = &panic_quiesce */
406	call	panic_trigger			/* %eax = panic_trigger() */
407
408vpanic_common:
409	/*
410	 * The panic_trigger result is in %eax from the call above, and
411	 * dtrace_panic places it in %eax before branching here.
412	 * The rdmsr instructions that follow below will clobber %eax so
413	 * we stash the panic_trigger result in %r11d.
414	 */
415	movl	%eax, %r11d
416	cmpl	$0, %r11d
417	je	0f
418
419	/*
420	 * If panic_trigger() was successful, we are the first to initiate a
421	 * panic: we now switch to the reserved panic_stack before continuing.
422	 */
423	leaq	panic_stack(%rip), %rsp
424	addq	$PANICSTKSIZE, %rsp
4250:	subq	$REGSIZE, %rsp
426	/*
427	 * Now that we've got everything set up, store the register values as
428	 * they were when we entered vpanic() to the designated location in
429	 * the regs structure we allocated on the stack.
430	 */
431#ifdef notyet
432	movq	0x0(%rbx), %rcx
433	movq	%rcx, REGOFF_RDI(%rsp)
434	movq	0x8(%rbx), %rcx
435	movq	%rcx, REGOFF_RSI(%rsp)
436	movq	0x10(%rbx), %rcx
437	movq	%rcx, REGOFF_RDX(%rsp)
438	movq	0x18(%rbx), %rcx
439	movq	%rcx, REGOFF_RCX(%rsp)
440	movq	0x20(%rbx), %rcx
441
442	movq	%rcx, REGOFF_R8(%rsp)
443	movq	0x28(%rbx), %rcx
444	movq	%rcx, REGOFF_R9(%rsp)
445	movq	0x30(%rbx), %rcx
446	movq	%rcx, REGOFF_RAX(%rsp)
447	movq	0x38(%rbx), %rcx
448	movq	%rcx, REGOFF_RBX(%rsp)
449	movq	0x58(%rbx), %rcx
450
451	movq	%rcx, REGOFF_RBP(%rsp)
452	movq	0x40(%rbx), %rcx
453	movq	%rcx, REGOFF_R10(%rsp)
454	movq	0x48(%rbx), %rcx
455	movq	%rcx, REGOFF_R11(%rsp)
456	movq	%r12, REGOFF_R12(%rsp)
457
458	movq	%r13, REGOFF_R13(%rsp)
459	movq	%r14, REGOFF_R14(%rsp)
460	movq	%r15, REGOFF_R15(%rsp)
461
462	xorl	%ecx, %ecx
463	movw	%ds, %cx
464	movq	%rcx, REGOFF_DS(%rsp)
465	movw	%es, %cx
466	movq	%rcx, REGOFF_ES(%rsp)
467	movw	%fs, %cx
468	movq	%rcx, REGOFF_FS(%rsp)
469	movw	%gs, %cx
470	movq	%rcx, REGOFF_GS(%rsp)
471
472	movq	$0, REGOFF_TRAPNO(%rsp)
473
474	movq	$0, REGOFF_ERR(%rsp)
475	leaq	vpanic(%rip), %rcx
476	movq	%rcx, REGOFF_RIP(%rsp)
477	movw	%cs, %cx
478	movzwq	%cx, %rcx
479	movq	%rcx, REGOFF_CS(%rsp)
480	movq	0x50(%rbx), %rcx
481	movq	%rcx, REGOFF_RFL(%rsp)
482	movq	%rbx, %rcx
483	addq	$0x60, %rcx
484	movq	%rcx, REGOFF_RSP(%rsp)
485	movw	%ss, %cx
486	movzwq	%cx, %rcx
487	movq	%rcx, REGOFF_SS(%rsp)
488
489	/*
490	 * panicsys(format, alist, rp, on_panic_stack)
491	 */
492	movq	REGOFF_RDI(%rsp), %rdi		/* format */
493	movq	REGOFF_RSI(%rsp), %rsi		/* alist */
494	movq	%rsp, %rdx			/* struct regs */
495	movl	%r11d, %ecx			/* on_panic_stack */
496	call	panicsys
497	addq	$REGSIZE, %rsp
498#endif
499	popq	%rdi
500	popq	%rsi
501	popq	%rdx
502	popq	%rcx
503	popq	%r8
504	popq	%r9
505	popq	%rax
506	popq	%rbx
507	popq	%r10
508	popq	%r11
509	popfq
510	leave
511	ret
512	END(vpanic)
513
514/*
515void
516dtrace_vpanic(const char *format, va_list alist)
517*/
518	ENTRY(dtrace_vpanic)			/* Initial stack layout: */
519
520	pushq	%rbp				/* | %rip | 	0x60	*/
521	movq	%rsp, %rbp			/* | %rbp |	0x58	*/
522	pushfq					/* | rfl  |	0x50	*/
523	pushq	%r11				/* | %r11 |	0x48	*/
524	pushq	%r10				/* | %r10 |	0x40	*/
525	pushq	%rbx				/* | %rbx |	0x38	*/
526	pushq	%rax				/* | %rax |	0x30	*/
527	pushq	%r9				/* | %r9  |	0x28	*/
528	pushq	%r8				/* | %r8  |	0x20	*/
529	pushq	%rcx				/* | %rcx |	0x18	*/
530	pushq	%rdx				/* | %rdx |	0x10	*/
531	pushq	%rsi				/* | %rsi |	0x8 alist */
532	pushq	%rdi				/* | %rdi |	0x0 format */
533
534	movq	%rsp, %rbx			/* %rbx = current %rsp */
535
536	leaq	panic_quiesce(%rip), %rdi	/* %rdi = &panic_quiesce */
537	call	dtrace_panic_trigger	/* %eax = dtrace_panic_trigger() */
538	jmp	vpanic_common
539
540	END(dtrace_vpanic)
541
542/*
543int
544panic_trigger(int *tp)
545*/
546	ENTRY(panic_trigger)
547	xorl	%eax, %eax
548	movl	$0xdefacedd, %edx
549	lock
550	  xchgl	%edx, (%rdi)
551	cmpl	$0, %edx
552	je	0f
553	movl	$0, %eax
554	ret
5550:	movl	$1, %eax
556	ret
557	END(panic_trigger)
558
559/*
560int
561dtrace_panic_trigger(int *tp)
562*/
563	ENTRY(dtrace_panic_trigger)
564	xorl	%eax, %eax
565	movl	$0xdefacedd, %edx
566	lock
567	  xchgl	%edx, (%rdi)
568	cmpl	$0, %edx
569	je	0f
570	movl	$0, %eax
571	ret
5720:	movl	$1, %eax
573	ret
574	END(dtrace_panic_trigger)
575