xref: /netbsd-src/sys/arch/arm/include/profile.h (revision ac344355818cabb30d36c6cae34daa86658a1d2e)
1*ac344355Sskrll /*	$NetBSD: profile.h,v 1.18 2018/01/24 09:04:45 skrll Exp $	*/
2c1f753f9Sreinoud 
3c1f753f9Sreinoud /*
48afb876fSbjh21  * Copyright (c) 2001 Ben Harris
5c1f753f9Sreinoud  * Copyright (c) 1995-1996 Mark Brinicombe
6c1f753f9Sreinoud  *
7c1f753f9Sreinoud  * Redistribution and use in source and binary forms, with or without
8c1f753f9Sreinoud  * modification, are permitted provided that the following conditions
9c1f753f9Sreinoud  * are met:
10c1f753f9Sreinoud  * 1. Redistributions of source code must retain the above copyright
11c1f753f9Sreinoud  *    notice, this list of conditions and the following disclaimer.
12c1f753f9Sreinoud  * 2. Redistributions in binary form must reproduce the above copyright
13c1f753f9Sreinoud  *    notice, this list of conditions and the following disclaimer in the
14c1f753f9Sreinoud  *    documentation and/or other materials provided with the distribution.
15c1f753f9Sreinoud  * 3. All advertising materials mentioning features or use of this software
16c1f753f9Sreinoud  *    must display the following acknowledgement:
17c1f753f9Sreinoud  *	This product includes software developed by Mark Brinicombe.
18c1f753f9Sreinoud  * 4. The name of the author may not be used to endorse or promote products
19c1f753f9Sreinoud  *    derived from this software without specific prior written permission.
20c1f753f9Sreinoud  *
21c1f753f9Sreinoud  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22c1f753f9Sreinoud  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23c1f753f9Sreinoud  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24c1f753f9Sreinoud  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25c1f753f9Sreinoud  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26c1f753f9Sreinoud  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27c1f753f9Sreinoud  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28c1f753f9Sreinoud  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29c1f753f9Sreinoud  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30c1f753f9Sreinoud  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31c1f753f9Sreinoud  */
32c1f753f9Sreinoud 
33c1f753f9Sreinoud #define	_MCOUNT_DECL void _mcount
34c1f753f9Sreinoud 
35c1f753f9Sreinoud /*
36c1f753f9Sreinoud  * Cannot implement mcount in C as GCC will trash the ip register when it
37c1f753f9Sreinoud  * pushes a trapframe. Pity we cannot insert assembly before the function
38c1f753f9Sreinoud  * prologue.
39c1f753f9Sreinoud  */
408afb876fSbjh21 
418afb876fSbjh21 #define MCOUNT_ASM_NAME "__mcount"
4259ce75e3Smatt #define	PLTSYM
4359ce75e3Smatt 
4435a69491Smatt #if !defined(__ARM_EABI__)
45c1f753f9Sreinoud #define	MCOUNT								\
4650a256a3Sperry 	__asm(".text");							\
4750a256a3Sperry 	__asm(".align	0");						\
4835a69491Smatt 	__asm(".arm");							\
4950a256a3Sperry 	__asm(".type	" MCOUNT_ASM_NAME ",%function");		\
5050a256a3Sperry 	__asm(".global	" MCOUNT_ASM_NAME);				\
5150a256a3Sperry 	__asm(MCOUNT_ASM_NAME ":");					\
52c1f753f9Sreinoud 	/*								\
53c1f753f9Sreinoud 	 * Preserve registers that are trashed during mcount		\
54c1f753f9Sreinoud 	 */								\
557b01c3f8Smatt 	__asm("push	{r0-r3, ip, lr}");				\
568afb876fSbjh21 	/* Check what mode we're in.  EQ => 32, NE => 26 */		\
5750a256a3Sperry 	__asm("teq	r0, r0");					\
5850a256a3Sperry 	__asm("teq	pc, r15");					\
59c1f753f9Sreinoud 	/*								\
60c1f753f9Sreinoud 	 * find the return address for mcount,				\
61c1f753f9Sreinoud 	 * and the return address for mcount's caller.			\
62c1f753f9Sreinoud 	 *								\
63c1f753f9Sreinoud 	 * frompcindex = pc pushed by call into self.			\
64c1f753f9Sreinoud 	 */								\
6550a256a3Sperry 	__asm("moveq	r0, ip");					\
6650a256a3Sperry 	__asm("bicne	r0, ip, #0xfc000003");	       			\
67c1f753f9Sreinoud 	/*								\
68c1f753f9Sreinoud 	 * selfpc = pc pushed by mcount call				\
69c1f753f9Sreinoud 	 */								\
7050a256a3Sperry 	__asm("moveq	r1, lr");					\
7150a256a3Sperry 	__asm("bicne	r1, lr, #0xfc000003");				\
72c1f753f9Sreinoud 	/*								\
73c1f753f9Sreinoud 	 * Call the real mcount code					\
74c1f753f9Sreinoud 	 */								\
7550a256a3Sperry 	__asm("bl	" ___STRING(_C_LABEL(_mcount)) PLTSYM);		\
76c1f753f9Sreinoud 	/*								\
77c1f753f9Sreinoud 	 * Restore registers that were trashed during mcount		\
78c1f753f9Sreinoud 	 */								\
79d342bce1Sjoerg 	__asm("pop	{r0-r3, lr}");					\
80d342bce1Sjoerg 	__asm("pop	{pc}");						\
817b01c3f8Smatt 	__asm(".size	" MCOUNT_ASM_NAME ", .-" MCOUNT_ASM_NAME);
82c8a1f8aeSjoerg #elif defined(__ARM_DWARF_EH__)
83c8a1f8aeSjoerg #define	MCOUNT								\
84c8a1f8aeSjoerg 	__asm(".text");							\
85c8a1f8aeSjoerg 	__asm(".align	0");						\
86c8a1f8aeSjoerg 	__asm(".arm");							\
87c8a1f8aeSjoerg 	__asm(".type	" MCOUNT_ASM_NAME ",%function");		\
88c8a1f8aeSjoerg 	__asm(".global	" MCOUNT_ASM_NAME);				\
89c8a1f8aeSjoerg 	__asm(MCOUNT_ASM_NAME ":");					\
90c8a1f8aeSjoerg 	__asm(".cfi_startproc");					\
91c8a1f8aeSjoerg 	/*								\
92c8a1f8aeSjoerg 	 * Preserve registers that are trashed during mcount		\
93c8a1f8aeSjoerg 	 */								\
94ca4be7acSmatt 	__asm("push	{r0-r3, ip, lr}");				\
95c8a1f8aeSjoerg 	__asm(".cfi_def_cfa_offset 24");				\
96c8a1f8aeSjoerg 	__asm(".cfi_offset 14, -4");					\
97ca4be7acSmatt 	__asm(".cfi_offset 12, -8");					\
98c8a1f8aeSjoerg 	__asm(".cfi_offset 3, -12");					\
99c8a1f8aeSjoerg 	__asm(".cfi_offset 2, -16");					\
100c8a1f8aeSjoerg 	__asm(".cfi_offset 1, -20");					\
101c8a1f8aeSjoerg 	__asm(".cfi_offset 0, -24");					\
102c8a1f8aeSjoerg 	/*								\
103c8a1f8aeSjoerg 	 * find the return address for mcount,				\
104c8a1f8aeSjoerg 	 * and the return address for mcount's caller.			\
105c8a1f8aeSjoerg 	 *								\
106c8a1f8aeSjoerg 	 * frompcindex = pc pushed by call into self.			\
107c8a1f8aeSjoerg 	 */								\
108c8a1f8aeSjoerg 	__asm("mov	r0, ip");					\
109c8a1f8aeSjoerg 	/*								\
110c8a1f8aeSjoerg 	 * selfpc = pc pushed by mcount call				\
111c8a1f8aeSjoerg 	 */								\
112c8a1f8aeSjoerg 	__asm("mov	r1, lr");					\
113c8a1f8aeSjoerg 	/*								\
114c8a1f8aeSjoerg 	 * Call the real mcount code					\
115c8a1f8aeSjoerg 	 */								\
116c8a1f8aeSjoerg 	__asm("bl	" ___STRING(_C_LABEL(_mcount)) PLTSYM);		\
117c8a1f8aeSjoerg 	/*								\
118c8a1f8aeSjoerg 	 * Restore registers that were trashed during mcount		\
119c8a1f8aeSjoerg 	 */								\
120d342bce1Sjoerg 	__asm("pop	{r0-r3, lr}");					\
121d342bce1Sjoerg 	__asm("pop	{pc}");						\
122c8a1f8aeSjoerg 	__asm(".cfi_endproc");						\
123c8a1f8aeSjoerg 	__asm(".size	" MCOUNT_ASM_NAME ", .-" MCOUNT_ASM_NAME);
1247b01c3f8Smatt #else
1257b01c3f8Smatt #define	MCOUNT								\
1267b01c3f8Smatt 	__asm(".text");							\
1277b01c3f8Smatt 	__asm(".align	0");						\
12835a69491Smatt 	__asm(".arm");							\
1297b01c3f8Smatt 	__asm(".type	" MCOUNT_ASM_NAME ",%function");		\
1307b01c3f8Smatt 	__asm(".global	" MCOUNT_ASM_NAME);				\
1317b01c3f8Smatt 	__asm(MCOUNT_ASM_NAME ":");					\
1326bb0d87bSmatt 	__asm(".fnstart");						\
1336bb0d87bSmatt 	__asm(".cfi_startproc");					\
1347b01c3f8Smatt 	/*								\
1357b01c3f8Smatt 	 * Preserve registers that are trashed during mcount		\
1367b01c3f8Smatt 	 */								\
137ca4be7acSmatt 	__asm("push	{r0-r3, ip, lr}");				\
138ca4be7acSmatt 	__asm(".save {r0-r3, lr}");					\
1396bb0d87bSmatt 	__asm(".cfi_def_cfa_offset 24");				\
1406bb0d87bSmatt 	__asm(".cfi_offset 14, -4");					\
141ca4be7acSmatt 	__asm(".cfi_offset 12, -8");					\
1426bb0d87bSmatt 	__asm(".cfi_offset 3, -12");					\
1436bb0d87bSmatt 	__asm(".cfi_offset 2, -16");					\
1446bb0d87bSmatt 	__asm(".cfi_offset 1, -20");					\
1456bb0d87bSmatt 	__asm(".cfi_offset 0, -24");					\
1467b01c3f8Smatt 	/*								\
1477b01c3f8Smatt 	 * find the return address for mcount,				\
1487b01c3f8Smatt 	 * and the return address for mcount's caller.			\
1497b01c3f8Smatt 	 *								\
1507b01c3f8Smatt 	 * frompcindex = pc pushed by call into self.			\
1517b01c3f8Smatt 	 */								\
1527b01c3f8Smatt 	__asm("mov	r0, ip");					\
1537b01c3f8Smatt 	/*								\
1547b01c3f8Smatt 	 * selfpc = pc pushed by mcount call				\
1557b01c3f8Smatt 	 */								\
1567b01c3f8Smatt 	__asm("mov	r1, lr");					\
1577b01c3f8Smatt 	/*								\
1587b01c3f8Smatt 	 * Call the real mcount code					\
1597b01c3f8Smatt 	 */								\
1607b01c3f8Smatt 	__asm("bl	" ___STRING(_C_LABEL(_mcount)) PLTSYM);		\
1617b01c3f8Smatt 	/*								\
1627b01c3f8Smatt 	 * Restore registers that were trashed during mcount		\
1637b01c3f8Smatt 	 */								\
164d342bce1Sjoerg 	__asm("pop	{r0-r3, lr}");					\
165d342bce1Sjoerg 	__asm("pop	{pc}");						\
1666bb0d87bSmatt 	__asm(".cfi_endproc");						\
1676bb0d87bSmatt 	__asm(".fnend");						\
1687b01c3f8Smatt 	__asm(".size	" MCOUNT_ASM_NAME ", .-" MCOUNT_ASM_NAME);
1697b01c3f8Smatt #endif
170c1f753f9Sreinoud 
171c1f753f9Sreinoud #ifdef _KERNEL
1720c57d872Sthorpej #include <arm/cpufunc.h>
173c1f753f9Sreinoud /*
174c1f753f9Sreinoud  * splhigh() and splx() are heavyweight, and call mcount().  Therefore
175c1f753f9Sreinoud  * we disabled interrupts (IRQ, but not FIQ) directly on the CPU.
176c1f753f9Sreinoud  *
177c1f753f9Sreinoud  * We're lucky that the CPSR and 's' both happen to be 'int's.
178c1f753f9Sreinoud  */
1794bb5ae3dSbriggs #define	MCOUNT_ENTER	s = __set_cpsr_c(0x0080, 0x0080);	/* kill IRQ */
1804bb5ae3dSbriggs #define	MCOUNT_EXIT	__set_cpsr_c(0xffffffff, s);	/* restore old value */
181c1f753f9Sreinoud #endif /* _KERNEL */
182