1 /*        $NetBSD: profile.h,v 1.18 2018/01/24 09:04:45 skrll Exp $   */
2 
3 /*
4  * Copyright (c) 2001 Ben Harris
5  * Copyright (c) 1995-1996 Mark Brinicombe
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *        This product includes software developed by Mark Brinicombe.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #define   _MCOUNT_DECL void _mcount
34 
35 /*
36  * Cannot implement mcount in C as GCC will trash the ip register when it
37  * pushes a trapframe. Pity we cannot insert assembly before the function
38  * prologue.
39  */
40 
41 #define MCOUNT_ASM_NAME "__mcount"
42 #define   PLTSYM
43 
44 #if !defined(__ARM_EABI__)
45 #define   MCOUNT                                                                          \
46           __asm(".text");                                                                 \
47           __asm(".align       0");                                                        \
48           __asm(".arm");                                                                  \
49           __asm(".type        " MCOUNT_ASM_NAME ",%function");                  \
50           __asm(".global      " MCOUNT_ASM_NAME);                               \
51           __asm(MCOUNT_ASM_NAME ":");                                           \
52           /*                                                                              \
53            * Preserve registers that are trashed during mcount                  \
54            */                                                                             \
55           __asm("push         {r0-r3, ip, lr}");                                \
56           /* Check what mode we're in.  EQ => 32, NE => 26 */                   \
57           __asm("teq          r0, r0");                                         \
58           __asm("teq          pc, r15");                                                  \
59           /*                                                                              \
60            * find the return address for mcount,                                \
61            * and the return address for mcount's caller.                        \
62            *                                                                              \
63            * frompcindex = pc pushed by call into self.                         \
64            */                                                                             \
65           __asm("moveq        r0, ip");                                         \
66           __asm("bicne        r0, ip, #0xfc000003");                                      \
67           /*                                                                              \
68            * selfpc = pc pushed by mcount call                                  \
69            */                                                                             \
70           __asm("moveq        r1, lr");                                         \
71           __asm("bicne        r1, lr, #0xfc000003");                                      \
72           /*                                                                              \
73            * Call the real mcount code                                          \
74            */                                                                             \
75           __asm("bl " ___STRING(_C_LABEL(_mcount)) PLTSYM);           \
76           /*                                                                              \
77            * Restore registers that were trashed during mcount                  \
78            */                                                                             \
79           __asm("pop          {r0-r3, lr}");                                              \
80           __asm("pop          {pc}");                                                     \
81           __asm(".size        " MCOUNT_ASM_NAME ", .-" MCOUNT_ASM_NAME);
82 #elif defined(__ARM_DWARF_EH__)
83 #define   MCOUNT                                                                          \
84           __asm(".text");                                                                 \
85           __asm(".align       0");                                                        \
86           __asm(".arm");                                                                  \
87           __asm(".type        " MCOUNT_ASM_NAME ",%function");                  \
88           __asm(".global      " MCOUNT_ASM_NAME);                               \
89           __asm(MCOUNT_ASM_NAME ":");                                           \
90           __asm(".cfi_startproc");                                              \
91           /*                                                                              \
92            * Preserve registers that are trashed during mcount                  \
93            */                                                                             \
94           __asm("push         {r0-r3, ip, lr}");                                \
95           __asm(".cfi_def_cfa_offset 24");                                      \
96           __asm(".cfi_offset 14, -4");                                          \
97           __asm(".cfi_offset 12, -8");                                          \
98           __asm(".cfi_offset 3, -12");                                          \
99           __asm(".cfi_offset 2, -16");                                          \
100           __asm(".cfi_offset 1, -20");                                          \
101           __asm(".cfi_offset 0, -24");                                          \
102           /*                                                                              \
103            * find the return address for mcount,                                \
104            * and the return address for mcount's caller.                        \
105            *                                                                              \
106            * frompcindex = pc pushed by call into self.                         \
107            */                                                                             \
108           __asm("mov          r0, ip");                                         \
109           /*                                                                              \
110            * selfpc = pc pushed by mcount call                                  \
111            */                                                                             \
112           __asm("mov          r1, lr");                                         \
113           /*                                                                              \
114            * Call the real mcount code                                          \
115            */                                                                             \
116           __asm("bl " ___STRING(_C_LABEL(_mcount)) PLTSYM);           \
117           /*                                                                              \
118            * Restore registers that were trashed during mcount                  \
119            */                                                                             \
120           __asm("pop          {r0-r3, lr}");                                              \
121           __asm("pop          {pc}");                                                     \
122           __asm(".cfi_endproc");                                                          \
123           __asm(".size        " MCOUNT_ASM_NAME ", .-" MCOUNT_ASM_NAME);
124 #else
125 #define   MCOUNT                                                                          \
126           __asm(".text");                                                                 \
127           __asm(".align       0");                                                        \
128           __asm(".arm");                                                                  \
129           __asm(".type        " MCOUNT_ASM_NAME ",%function");                  \
130           __asm(".global      " MCOUNT_ASM_NAME);                               \
131           __asm(MCOUNT_ASM_NAME ":");                                           \
132           __asm(".fnstart");                                                    \
133           __asm(".cfi_startproc");                                              \
134           /*                                                                              \
135            * Preserve registers that are trashed during mcount                  \
136            */                                                                             \
137           __asm("push         {r0-r3, ip, lr}");                                \
138           __asm(".save {r0-r3, lr}");                                           \
139           __asm(".cfi_def_cfa_offset 24");                                      \
140           __asm(".cfi_offset 14, -4");                                          \
141           __asm(".cfi_offset 12, -8");                                          \
142           __asm(".cfi_offset 3, -12");                                          \
143           __asm(".cfi_offset 2, -16");                                          \
144           __asm(".cfi_offset 1, -20");                                          \
145           __asm(".cfi_offset 0, -24");                                          \
146           /*                                                                              \
147            * find the return address for mcount,                                \
148            * and the return address for mcount's caller.                        \
149            *                                                                              \
150            * frompcindex = pc pushed by call into self.                         \
151            */                                                                             \
152           __asm("mov          r0, ip");                                         \
153           /*                                                                              \
154            * selfpc = pc pushed by mcount call                                  \
155            */                                                                             \
156           __asm("mov          r1, lr");                                         \
157           /*                                                                              \
158            * Call the real mcount code                                          \
159            */                                                                             \
160           __asm("bl " ___STRING(_C_LABEL(_mcount)) PLTSYM);           \
161           /*                                                                              \
162            * Restore registers that were trashed during mcount                  \
163            */                                                                             \
164           __asm("pop          {r0-r3, lr}");                                              \
165           __asm("pop          {pc}");                                                     \
166           __asm(".cfi_endproc");                                                          \
167           __asm(".fnend");                                                      \
168           __asm(".size        " MCOUNT_ASM_NAME ", .-" MCOUNT_ASM_NAME);
169 #endif
170 
171 #ifdef _KERNEL
172 #include <arm/cpufunc.h>
173 /*
174  * splhigh() and splx() are heavyweight, and call mcount().  Therefore
175  * we disabled interrupts (IRQ, but not FIQ) directly on the CPU.
176  *
177  * We're lucky that the CPSR and 's' both happen to be 'int's.
178  */
179 #define   MCOUNT_ENTER        s = __set_cpsr_c(0x0080, 0x0080);       /* kill IRQ */
180 #define   MCOUNT_EXIT         __set_cpsr_c(0xffffffff, s);  /* restore old value */
181 #endif /* _KERNEL */
182