| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-4-Clause |
| 3 | * |
| 4 | * Copyright (C) 1995, 1996 Wolfgang Solfrank. |
| 5 | * Copyright (C) 1995, 1996 TooLs GmbH. |
| 6 | * All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer in the |
| 15 | * documentation and/or other materials provided with the distribution. |
| 16 | * 3. All advertising materials mentioning features or use of this software |
| 17 | * must display the following acknowledgement: |
| 18 | *	This product includes software developed by TooLs GmbH. |
| 19 | * 4. The name of TooLs GmbH may not be used to endorse or promote products |
| 20 | * derived from this software without specific prior written permission. |
| 21 | * |
| 22 | * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR |
| 23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 25 | * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 27 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| 28 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 30 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| 31 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 32 | * |
| 33 | *	$NetBSD: asm.h,v 1.6.18.1 2000/07/25 08:37:14 kleink Exp $ |
| 34 | */ |
| 35 | |
| 36 | #ifndef _MACHINE_ASM_H_ |
| 37 | #define	_MACHINE_ASM_H_ |
| 38 | |
| 39 | #include <sys/cdefs.h> |
| 40 | |
| 41 | #if defined(PIC) && !defined(__powerpc64__) |
| 42 | #define	PIC_PROLOGUE	XXX |
| 43 | #define	PIC_EPILOGUE	XXX |
| 44 | #define	PIC_PLT(x)	x@plt |
| 45 | #ifdef	__STDC__ |
| 46 | #define	PIC_GOT(x)	XXX |
| 47 | #else	/* not __STDC__ */ |
| 48 | #define	PIC_GOT(x)	XXX |
| 49 | #endif	/* __STDC__ */ |
| 50 | #else |
| 51 | #define	PIC_PROLOGUE |
| 52 | #define	PIC_EPILOGUE |
| 53 | #define	PIC_PLT(x)	x |
| 54 | #define PIC_GOT(x)	x |
| 55 | #endif |
| 56 | |
| 57 | #define	CNAME(csym)		csym |
| 58 | #define	ASMNAME(asmsym)		asmsym |
| 59 | #ifdef __powerpc64__ |
| 60 | #define	HIDENAME(asmsym)	__CONCAT(_,asmsym) |
| 61 | #else |
| 62 | #define	HIDENAME(asmsym)	__CONCAT(.,asmsym) |
| 63 | #endif |
| 64 | |
| 65 | #if !defined(_CALL_ELF) || _CALL_ELF == 1 |
| 66 | #ifdef _KERNEL |
| 67 | /* ELFv1 kernel uses global dot symbols */ |
| 68 | #define	DOT_LABEL(name)		__CONCAT(.,name) |
| 69 | #define	TYPE_ENTRY(name)	.size	name,24; \ |
| 70 | 				.type	DOT_LABEL(name),@function; \ |
| 71 | 				.globl	DOT_LABEL(name); |
| 72 | #define	END_SIZE(name)		.size	DOT_LABEL(name),.-DOT_LABEL(name); |
| 73 | #else /* !_KERNEL */ |
| 74 | /* ELFv1 user code uses local function entry points */ |
| 75 | #define	DOT_LABEL(name)		__CONCAT(.L.,name) |
| 76 | #define	TYPE_ENTRY(name)	.type	name,@function; |
| 77 | #define	END_SIZE(name)		.size	name,.-DOT_LABEL(name); |
| 78 | #endif /* _KERNEL */ |
| 79 | #else |
| 80 | /* ELFv2 doesn't have any of this complication */ |
| 81 | #define	DOT_LABEL(name)		name |
| 82 | #define	TYPE_ENTRY(name)	.type	name,@function; |
| 83 | #define	END_SIZE(name)		.size	name,.-DOT_LABEL(name); |
| 84 | #endif |
| 85 | |
| 86 | #define	_GLOBAL(name) \ |
| 87 | 	.data; \ |
| 88 | 	.p2align 2; \ |
| 89 | 	.globl	name; \ |
| 90 | 	name: |
| 91 | |
| 92 | #ifdef __powerpc64__ |
| 93 | #define TOC_NAME_FOR_REF(name)	__CONCAT(.L,name) |
| 94 | #define	TOC_REF(name)	TOC_NAME_FOR_REF(name)@toc |
| 95 | #define TOC_ENTRY(name) \ |
| 96 | 	.section ".toc","aw"; \ |
| 97 | 	TOC_NAME_FOR_REF(name): \ |
| 98 | .tc name[TC],name |
| 99 | #endif |
| 100 | |
| 101 | #ifdef __powerpc64__ |
| 102 | |
| 103 | #if !defined(_CALL_ELF) || _CALL_ELF == 1 |
| 104 | #define	_ENTRY(name) \ |
| 105 | 	.section ".text"; \ |
| 106 | 	.p2align 2; \ |
| 107 | 	.globl	name; \ |
| 108 | 	.section ".opd","aw"; \ |
| 109 | 	.p2align 3; \ |
| 110 | name: \ |
| 111 | 	.quad	DOT_LABEL(name),.TOC.@tocbase,0; \ |
| 112 | 	.previous; \ |
| 113 | 	.p2align 4; \ |
| 114 | 	TYPE_ENTRY(name) \ |
| 115 | DOT_LABEL(name): \ |
| 116 | 	.cfi_startproc |
| 117 | #define	_NAKED_ENTRY(name)	_ENTRY(name) |
| 118 | #else |
| 119 | #define	_ENTRY(name) \ |
| 120 | 	.text; \ |
| 121 | 	.p2align 4; \ |
| 122 | 	.globl	name; \ |
| 123 | 	.type	name,@function; \ |
| 124 | name: \ |
| 125 | 	.cfi_startproc; \ |
| 126 | 	addis	%r2, %r12, (.TOC.-name)@ha; \ |
| 127 | 	addi	%r2, %r2, (.TOC.-name)@l; \ |
| 128 | 	.localentry name, .-name; |
| 129 | |
| 130 | /* "Naked" function entry. No TOC prologue for ELFv2. */ |
| 131 | #define	_NAKED_ENTRY(name) \ |
| 132 | 	.text; \ |
| 133 | 	.p2align 4; \ |
| 134 | 	.globl	name; \ |
| 135 | 	.type	name,@function; \ |
| 136 | name: \ |
| 137 | 	.cfi_startproc; \ |
| 138 | 	.localentry name, .-name; |
| 139 | #endif |
| 140 | |
| 141 | #define	_END(name) \ |
| 142 | 	.cfi_endproc; \ |
| 143 | 	.long	0; \ |
| 144 | 	.byte	0,0,0,0,0,0,0,0; \ |
| 145 | 	END_SIZE(name) |
| 146 | |
| 147 | #define	LOAD_ADDR(reg, var) \ |
| 148 | 	lis	reg, var@highest; \ |
| 149 | 	ori	reg, reg, var@higher; \ |
| 150 | 	rldicr	reg, reg, 32, 31; \ |
| 151 | 	oris	reg, reg, var@h; \ |
| 152 | 	ori	reg, reg, var@l; |
| 153 | #else /* !__powerpc64__ */ |
| 154 | #define	_ENTRY(name) \ |
| 155 | 	.text; \ |
| 156 | 	.p2align 4; \ |
| 157 | 	.globl	name; \ |
| 158 | 	.type	name,@function; \ |
| 159 | name: \ |
| 160 | 	.cfi_startproc |
| 161 | #define	_END(name) \ |
| 162 | 	.cfi_endproc; \ |
| 163 | 	.size	name, . - name |
| 164 | |
| 165 | #define _NAKED_ENTRY(name)	_ENTRY(name) |
| 166 | |
| 167 | #define	LOAD_ADDR(reg, var) \ |
| 168 | 	lis	reg, var@ha; \ |
| 169 | 	ori	reg, reg, var@l; |
| 170 | #endif /* __powerpc64__ */ |
| 171 | |
| 172 | #if defined(PROF) || (defined(_KERNEL) && defined(GPROF)) |
| 173 | # ifdef __powerpc64__ |
| 174 | # define	_PROF_PROLOGUE	mflr 0;					\ |
| 175 | 				std 3,48(1);				\ |
| 176 | 				std 4,56(1);				\ |
| 177 | 				std 5,64(1);				\ |
| 178 | 				std 0,16(1);				\ |
| 179 | 				stdu 1,-112(1);				\ |
| 180 | 				bl _mcount;				\ |
| 181 | 				nop;					\ |
| 182 | 				ld 0,112+16(1);				\ |
| 183 | 				ld 3,112+48(1);				\ |
| 184 | 				ld 4,112+56(1);				\ |
| 185 | 				ld 5,112+64(1);				\ |
| 186 | 				mtlr 0;					\ |
| 187 | 				addi 1,1,112 |
| 188 | # else |
| 189 | # define	_PROF_PROLOGUE	mflr 0; stw 0,4(1); bl _mcount |
| 190 | # endif |
| 191 | #else |
| 192 | # define	_PROF_PROLOGUE |
| 193 | #endif |
| 194 | |
| 195 | #define	ASEND(y)	_END(ASMNAME(y)) |
| 196 | #define	ASENTRY(y)	_ENTRY(ASMNAME(y)); _PROF_PROLOGUE |
| 197 | #define	END(y)		_END(CNAME(y)) |
| 198 | #define	ENTRY(y)	_ENTRY(CNAME(y)); _PROF_PROLOGUE |
| 199 | #define	GLOBAL(y)	_GLOBAL(CNAME(y)) |
| 200 | |
| 201 | #define	ASENTRY_NOPROF(y)	_ENTRY(ASMNAME(y)) |
| 202 | #define	ENTRY_NOPROF(y)		_ENTRY(CNAME(y)) |
| 203 | |
| 204 | /* Load NIA without affecting branch prediction */ |
| 205 | #define	LOAD_LR_NIA	bcl	20, 31, .+4 |
| 206 | |
| 207 | /* |
| 208 | * Magic sequence to return to native endian. |
| 209 | * Overwrites r0 and r11. |
| 210 | * |
| 211 | * The encoding of the instruction "tdi 0, %r0, 0x48" in opposite endian |
| 212 | * happens to be "b . + 8". This is useful because we can write a sequence |
| 213 | * of instructions that can execute in either endian. |
| 214 | * |
| 215 | * Use a sequence of handcoded instructions that switches contexts to the |
| 216 | * instruction following the sequence, but with the correct PSL_LE bit. |
| 217 | * |
| 218 | * The same sequence works for both BE and LE because the xori will flip |
| 219 | * the bit to the other state, and the code only runs when running in the |
| 220 | * wrong endian. |
| 221 | * |
| 222 | * This sequence is NMI-reentrant. |
| 223 | * |
| 224 | * Do not change the length of this sequence without looking at the users, |
| 225 | * this is used in size-constrained places like the reset vector! |
| 226 | */ |
| 227 | #define	RETURN_TO_NATIVE_ENDIAN						 \ |
| 228 | 	tdi	0, %r0, 0x48;	/* Endian swapped: b . + 8		*/\ |
| 229 | 	b	1f;		/* Will fall through to here if correct */\ |
| 230 | 	.long	0xa600607d;	/* mfmsr %r11				*/\ |
| 231 | 	.long	0x00000038;	/* li %r0, 0				*/\ |
| 232 | 	.long	0x6401617d;	/* mtmsrd %r0, 1 (L=1 EE,RI bits only)	*/\ |
| 233 | 	.long	0x01006b69;	/* xori %r11, %r11, 0x1 (PSL_LE)	*/\ |
| 234 | 	.long	0xa602087c;	/* mflr %r0				*/\ |
| 235 | 	.long	0x05009f42;	/* LOAD_LR_NIA				*/\ |
| 236 | 	.long	0xa6037b7d;	/* 0: mtsrr1 %r11			*/\ |
| 237 | 	.long	0xa602687d;	/* mflr	%r11				*/\ |
| 238 | 	.long	0x18006b39;	/* addi	%r11, %r11, (1f - 0b)		*/\ |
| 239 | 	.long	0xa6037a7d;	/* mtsrr0 %r11				*/\ |
| 240 | 	.long	0xa603087c;	/* mtlr %r0				*/\ |
| 241 | 	.long	0x2400004c;	/* rfid					*/\ |
| 242 | 1:	/* RETURN_TO_NATIVE_ENDIAN */ |
| 243 | |
| 244 | #define	ASMSTR		.asciz |
| 245 | |
| 246 | #define	RCSID(x)	.text; .asciz x |
| 247 | |
| 248 | #undef __FBSDID |
| 249 | #if !defined(lint) && !defined(STRIP_FBSDID) |
| 250 | #define __FBSDID(s)	.ident s |
| 251 | #else |
| 252 | #define __FBSDID(s)	/* nothing */ |
| 253 | #endif /* not lint and not STRIP_FBSDID */ |
| 254 | |
| 255 | #define	WEAK_REFERENCE(sym, alias)				\ |
| 256 | 	.weak alias;						\ |
| 257 | 	.equ alias,sym |
| 258 | |
| 259 | #ifdef __STDC__ |
| 260 | #define	WARN_REFERENCES(_sym,_msg)				\ |
| 261 | 	.section .gnu.warning. ## _sym ; .ascii _msg ; .text |
| 262 | #else |
| 263 | #define	WARN_REFERENCES(_sym,_msg)				\ |
| 264 | 	.section .gnu.warning./**/_sym ; .ascii _msg ; .text |
| 265 | #endif /* __STDC__ */ |
| 266 | |
| 267 | #endif /* !_MACHINE_ASM_H_ */ |