4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
25 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
31 #include <machine/asmacros.h>
32 #include <sys/cpuvar_defs.h>
33 #include <sys/dtrace.h>
38 .type calltrap,@function
39 ENTRY(dtrace_invop_start)
41 pushl %eax /* push %eax -- may be return value */
42 pushl %esp /* push stack pointer */
43 addl $48, (%esp) /* adjust to incoming args */
44 pushl 40(%esp) /* push calling EIP */
47 * Call dtrace_invop to let it check if the exception was
48 * a fbt one. The return value in %eax will tell us what
49 * dtrace_invop wants us to do.
54 * We pushed 3 times for the arguments to dtrace_invop,
55 * so we need to increment the stack pointer to get rid of
59 ALTENTRY(dtrace_invop_callsite)
60 cmpl $DTRACE_INVOP_PUSHL_EBP, %eax
62 cmpl $DTRACE_INVOP_POPL_EBP, %eax
64 cmpl $DTRACE_INVOP_LEAVE, %eax
66 cmpl $DTRACE_INVOP_NOP, %eax
69 /* When all else fails handle the trap in the usual way. */
70 jmpl *dtrace_invop_calltrap_addr
74 * We must emulate a "pushl %ebp". To do this, we pull the stack
75 * down 4 bytes, and then store the base pointer.
78 subl $4, %esp /* make room for %ebp */
79 pushl %eax /* push temp */
80 movl 8(%esp), %eax /* load calling EIP */
81 incl %eax /* increment over LOCK prefix */
82 movl %eax, 4(%esp) /* store calling EIP */
83 movl 12(%esp), %eax /* load calling CS */
84 movl %eax, 8(%esp) /* store calling CS */
85 movl 16(%esp), %eax /* load calling EFLAGS */
86 movl %eax, 12(%esp) /* store calling EFLAGS */
87 movl %ebp, 16(%esp) /* push %ebp */
88 popl %eax /* pop off temp */
89 iret /* Return from interrupt. */
92 * We must emulate a "popl %ebp". To do this, we do the opposite of
93 * the above: we remove the %ebp from the stack, and squeeze up the
94 * saved state from the trap.
97 pushl %eax /* push temp */
98 movl 16(%esp), %ebp /* pop %ebp */
99 movl 12(%esp), %eax /* load calling EFLAGS */
100 movl %eax, 16(%esp) /* store calling EFLAGS */
101 movl 8(%esp), %eax /* load calling CS */
102 movl %eax, 12(%esp) /* store calling CS */
103 movl 4(%esp), %eax /* load calling EIP */
104 incl %eax /* increment over LOCK prefix */
105 movl %eax, 8(%esp) /* store calling EIP */
106 popl %eax /* pop off temp */
107 addl $4, %esp /* adjust stack pointer */
108 iret /* Return from interrupt. */
111 * We must emulate a "leave", which is the same as a "movl %ebp, %esp"
112 * followed by a "popl %ebp". This looks similar to the above, but
113 * requires two temporaries: one for the new base pointer, and one
114 * for the staging register.
117 pushl %eax /* push temp */
118 pushl %ebx /* push temp */
119 movl %ebp, %ebx /* set temp to old %ebp */
120 movl (%ebx), %ebp /* pop %ebp */
121 movl 16(%esp), %eax /* load calling EFLAGS */
122 movl %eax, (%ebx) /* store calling EFLAGS */
123 movl 12(%esp), %eax /* load calling CS */
124 movl %eax, -4(%ebx) /* store calling CS */
125 movl 8(%esp), %eax /* load calling EIP */
126 incl %eax /* increment over LOCK prefix */
127 movl %eax, -8(%ebx) /* store calling EIP */
128 movl %ebx, -4(%esp) /* temporarily store new %esp */
129 popl %ebx /* pop off temp */
130 popl %eax /* pop off temp */
131 movl -12(%esp), %esp /* set stack pointer */
132 subl $8, %esp /* adjust for three pushes, one pop */
133 iret /* return from interrupt */
136 * We must emulate a "nop". This is obviously not hard: we need only
137 * advance the %eip by one.
141 iret /* return from interrupt */
143 END(dtrace_invop_start)
146 void dtrace_invop_init(void)
148 ENTRY(dtrace_invop_init)
149 movl $dtrace_invop_start, dtrace_invop_jump_addr
151 END(dtrace_invop_init)
154 void dtrace_invop_uninit(void)
156 ENTRY(dtrace_invop_uninit)
157 movl $0, dtrace_invop_jump_addr
159 END(dtrace_invop_uninit)
162 greg_t dtrace_getfp(void)
171 uint32_t dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
175 ALTENTRY(dtrace_casptr)
180 cmpxchgl %ecx, (%edx)
186 uintptr_t dtrace_caller(int aframes)
195 void dtrace_copy(uintptr_t src, uintptr_t dest, size_t size)
204 movl 8(%ebp), %esi /* Load source address */
205 movl 12(%ebp), %edi /* Load destination address */
206 movl 16(%ebp), %ecx /* Load count */
207 repz /* Repeat for count... */
208 smovb /* move from %ds:si to %es:di */
218 void dtrace_copystr(uintptr_t uaddr, uintptr_t kaddr, size_t size)
221 ENTRY(dtrace_copystr)
223 pushl %ebp /* Setup stack frame */
225 pushl %ebx /* Save registers */
227 movl 8(%ebp), %ebx /* Load source address */
228 movl 12(%ebp), %edx /* Load destination address */
229 movl 16(%ebp), %ecx /* Load count */
232 movb (%ebx), %al /* Load from source */
233 movb %al, (%edx) /* Store to destination */
234 incl %ebx /* Increment source pointer */
235 incl %edx /* Increment destination pointer */
236 decl %ecx /* Decrement remaining count */
251 uintptr_t dtrace_fulword(void *addr)
254 ENTRY(dtrace_fulword)
262 uint8_t dtrace_fuword8_nocheck(void *addr)
265 ENTRY(dtrace_fuword8_nocheck)
270 END(dtrace_fuword8_nocheck)
273 uint16_t dtrace_fuword16_nocheck(void *addr)
276 ENTRY(dtrace_fuword16_nocheck)
281 END(dtrace_fuword16_nocheck)
284 uint32_t dtrace_fuword32_nocheck(void *addr)
287 ENTRY(dtrace_fuword32_nocheck)
292 END(dtrace_fuword32_nocheck)
295 uint64_t dtrace_fuword64_nocheck(void *addr)
298 ENTRY(dtrace_fuword64_nocheck)
305 END(dtrace_fuword64_nocheck)
308 void dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, int fault, int fltoffs, uintptr_t illval)
311 ENTRY(dtrace_probe_error)
320 pushl dtrace_probeid_error
325 END(dtrace_probe_error)
328 void dtrace_membar_producer(void)
331 ENTRY(dtrace_membar_producer)
332 rep; ret /* use 2 byte return instruction when branch target */
333 /* AMD Software Optimization Guide - Section 6.2 */
334 END(dtrace_membar_producer)
337 void dtrace_membar_consumer(void)
340 ENTRY(dtrace_membar_consumer)
341 rep; ret /* use 2 byte return instruction when branch target */
342 /* AMD Software Optimization Guide - Section 6.2 */
343 END(dtrace_membar_consumer)
346 dtrace_icookie_t dtrace_interrupt_disable(void)
348 ENTRY(dtrace_interrupt_disable)
353 END(dtrace_interrupt_disable)
356 void dtrace_interrupt_enable(dtrace_icookie_t cookie)
358 ENTRY(dtrace_interrupt_enable)
363 END(dtrace_interrupt_enable)
366 * The panic() and cmn_err() functions invoke vpanic() as a common entry point
367 * into the panic code implemented in panicsys(). vpanic() is responsible
368 * for passing through the format string and arguments, and constructing a
369 * regs structure on the stack into which it saves the current register
370 * values. If we are not dying due to a fatal trap, these registers will
371 * then be preserved in panicbuf as the current processor state. Before
372 * invoking panicsys(), vpanic() activates the first panic trigger (see
373 * common/os/panic.c) and switches to the panic_stack if successful. Note that
374 * DTrace takes a slightly different panic path if it must panic from probe
375 * context. Instead of calling panic, it calls into dtrace_vpanic(), which
376 * sets up the initial stack as vpanic does, calls dtrace_panic_trigger(), and
377 * branches back into vpanic().
380 void vpanic(const char *format, va_list alist)
382 ENTRY(vpanic) /* Initial stack layout: */
384 pushl %ebp /* | %eip | 20 */
385 movl %esp, %ebp /* | %ebp | 16 */
386 pushl %eax /* | %eax | 12 */
387 pushl %ebx /* | %ebx | 8 */
388 pushl %ecx /* | %ecx | 4 */
389 pushl %edx /* | %edx | 0 */
391 movl %esp, %ebx /* %ebx = current stack pointer */
393 lea panic_quiesce, %eax /* %eax = &panic_quiesce */
394 pushl %eax /* push &panic_quiesce */
395 call panic_trigger /* %eax = panic_trigger() */
396 addl $4, %esp /* reset stack pointer */
399 cmpl $0, %eax /* if (%eax == 0) */
403 * If panic_trigger() was successful, we are the first to initiate a
404 * panic: we now switch to the reserved panic_stack before continuing.
406 lea panic_stack, %esp /* %esp = panic_stack */
407 addl $PANICSTKSIZE, %esp /* %esp += PANICSTKSIZE */
409 0: subl $REGSIZE, %esp /* allocate struct regs */
412 * Now that we've got everything set up, store the register values as
413 * they were when we entered vpanic() to the designated location in
414 * the regs structure we allocated on the stack.
418 mov %edx, REGOFF_GS(%esp)
420 mov %edx, REGOFF_FS(%esp)
422 mov %edx, REGOFF_ES(%esp)
424 mov %edx, REGOFF_DS(%esp)
425 movl %edi, REGOFF_EDI(%esp)
426 movl %esi, REGOFF_ESI(%esp)
428 movl %ecx, REGOFF_EBP(%esp)
431 movl %ecx, REGOFF_ESP(%esp)
433 movl %ecx, REGOFF_EBX(%esp)
435 movl %ecx, REGOFF_EDX(%esp)
437 movl %ecx, REGOFF_ECX(%esp)
439 movl %ecx, REGOFF_EAX(%esp)
440 movl $0, REGOFF_TRAPNO(%esp)
441 movl $0, REGOFF_ERR(%esp)
443 movl %ecx, REGOFF_EIP(%esp)
445 movl %edx, REGOFF_CS(%esp)
448 movl %ecx, REGOFF_EFL(%esp)
449 movl $0, REGOFF_UESP(%esp)
451 movl %edx, REGOFF_SS(%esp)
453 movl %esp, %ecx /* %ecx = ®s */
454 pushl %eax /* push on_panic_stack */
455 pushl %ecx /* push ®s */
456 movl 12(%ebp), %ecx /* %ecx = alist */
457 pushl %ecx /* push alist */
458 movl 8(%ebp), %ecx /* %ecx = format */
459 pushl %ecx /* push format */
460 call panicsys /* panicsys(); */
461 addl $16, %esp /* pop arguments */
474 void dtrace_vpanic(const char *format, va_list alist)
476 ENTRY(dtrace_vpanic) /* Initial stack layout: */
478 pushl %ebp /* | %eip | 20 */
479 movl %esp, %ebp /* | %ebp | 16 */
480 pushl %eax /* | %eax | 12 */
481 pushl %ebx /* | %ebx | 8 */
482 pushl %ecx /* | %ecx | 4 */
483 pushl %edx /* | %edx | 0 */
485 movl %esp, %ebx /* %ebx = current stack pointer */
487 lea panic_quiesce, %eax /* %eax = &panic_quiesce */
488 pushl %eax /* push &panic_quiesce */
489 call dtrace_panic_trigger /* %eax = dtrace_panic_trigger() */
490 addl $4, %esp /* reset stack pointer */
491 jmp vpanic_common /* jump back to common code */
497 panic_trigger(int *tp)
501 movl $0xdefacedd, %edx
514 dtrace_panic_trigger(int *tp)
516 ENTRY(dtrace_panic_trigger)
518 movl $0xdefacedd, %edx
527 END(dtrace_panic_trigger)