/*	$OpenBSD: asm.h,v 1.24 2023/04/17 00:02:14 deraadt Exp $	*/
/*	$NetBSD: asm.h,v 1.2 2003/05/02 18:05:47 yamt Exp $	*/

/*-
 * Copyright (c) 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * William Jolitz.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)asm.h	5.5 (Berkeley) 5/7/91
 */

#ifndef _MACHINE_ASM_H_
#define _MACHINE_ASM_H_

#ifdef __PIC__
#define PIC_PLT(x)	x@PLT
#define PIC_GOT(x)	x@GOTPCREL(%rip)
#else
#define PIC_PLT(x)	x
#define PIC_GOT(x)	x
#endif

# define _C_LABEL(x)	x
#define	_ASM_LABEL(x)	x

#define CVAROFF(x,y)		(x+y)(%rip)

#ifdef __STDC__
# define __CONCAT(x,y)	x ## y
# define __STRING(x)	#x
#else
# define __CONCAT(x,y)	x/**/y
# define __STRING(x)	"x"
#endif

/* let kernels and others override entrypoint alignment */
#ifndef _ALIGN_TEXT
#define _ALIGN_TEXT	.align	16, 0x90
#endif
#define _ALIGN_TRAPS	.align	16, 0xcc

#define	_FENTRY(x)	.type x,@function; x:

/* NB == No Binding: use .globl or .weak as necessary */
#define	NENTRY_NB(x)	\
	.text; _ALIGN_TEXT; _FENTRY(x)
#define _ENTRY_NB(x) \
	.text; _ALIGN_TRAPS; _FENTRY(x)
#define _ENTRY(x)	.globl x; _ENTRY_NB(x)
#define _NENTRY(x)	.globl x; NENTRY_NB(x)

#ifdef _KERNEL
#define	KUTEXT	.section .kutext, "ax", @progbits

#define	KUTEXT_PAGE_START	.pushsection .kutext.page, "a", @progbits
#define	KTEXT_PAGE_START	.pushsection .ktext.page, "ax", @progbits
#define	KUTEXT_PAGE_END		.popsection
#define	KTEXT_PAGE_END		.popsection

#define	IDTVEC(name) \
	KUTEXT; _ALIGN_TRAPS; IDTVEC_NOALIGN(name); endbr64
#define	GENTRY(x)		.globl x; _FENTRY(x)
#define	IDTVEC_NOALIGN(name)	GENTRY(X ## name)
#define	IDTVEC_ALIAS(alias,sym)						\
	.global X ## alias;						\
	X ## alias = X ## sym;
#define	KIDTVEC(name) \
	.text; _ALIGN_TRAPS; IDTVEC_NOALIGN(name); endbr64
#define	KIDTVEC_FALLTHROUGH(name) \
	_ALIGN_TEXT; IDTVEC_NOALIGN(name)
#define KUENTRY(x) \
	KUTEXT; _ALIGN_TRAPS; GENTRY(x)

/* Return stack refill, to prevent speculation attacks on natural returns */
#define	RET_STACK_REFILL_WITH_RCX	\
		mov	$8,%rcx		; \
		_ALIGN_TEXT		; \
	3:	call	5f		; \
	4:	pause			; \
		lfence			; \
		call	4b		; \
		_ALIGN_TRAPS		; \
	5:	call	7f		; \
	6:	pause			; \
		lfence			; \
		call	6b		; \
		_ALIGN_TRAPS		; \
	7:	loop	3b		; \
		add	$(16*8),%rsp

#endif /* _KERNEL */

#ifdef __STDC__
#define CPUVAR(off)	%gs:CPU_INFO_ ## off
#else
#define CPUVAR(off)     %gs:CPU_INFO_/**/off
#endif


#if defined(PROF) || defined(GPROF)
# define _PROF_PROLOGUE	\
	pushq %rbp; leaq (%rsp),%rbp; call PIC_PLT(__mcount); popq %rbp
#else
# define _PROF_PROLOGUE
#endif

#if defined(_RET_PROTECTOR)
# define RETGUARD_SETUP_OFF(x, reg, off) \
	RETGUARD_SYMBOL(x); \
	movq (__retguard_ ## x)(%rip), %reg; \
	xorq off(%rsp), %reg
# define RETGUARD_SETUP(x, reg) \
	RETGUARD_SETUP_OFF(x, reg, 0)
# define RETGUARD_CHECK(x, reg) \
	xorq (%rsp), %reg; \
	cmpq (__retguard_ ## x)(%rip), %reg; \
	je 66f; \
	int3; int3; \
	.zero (0xf - ((. + 3 - x) & 0xf)), 0xcc; \
66:
# define RETGUARD_PUSH(reg) \
	pushq %reg
# define RETGUARD_POP(reg) \
	popq %reg
# define RETGUARD_SYMBOL(x) \
	.ifndef __retguard_ ## x; \
	.hidden __retguard_ ## x; \
	.type   __retguard_ ## x,@object; \
	.pushsection .openbsd.randomdata.retguard,"aw",@progbits; \
	.weak   __retguard_ ## x; \
	.p2align 3; \
	__retguard_ ## x: ; \
	.quad 0; \
	.size __retguard_ ## x, 8; \
	.popsection; \
	.endif
#else
# define RETGUARD_SETUP_OFF(x, reg, off)
# define RETGUARD_SETUP(x, reg)
# define RETGUARD_CHECK(x, reg)
# define RETGUARD_PUSH(reg)
# define RETGUARD_POP(reg)
# define RETGUARD_SYMBOL(x)
#endif

#define	ENTRY(y)	_ENTRY(y); endbr64; _PROF_PROLOGUE
#define	NENTRY(y)	_NENTRY(y)
#define	ASENTRY(y)	_NENTRY(y); endbr64; _PROF_PROLOGUE
#define	ENTRY_NB(y)	_ENTRY_NB(y); endbr64; _PROF_PROLOGUE
#define	END(y)		.size y, . - y

#define	STRONG_ALIAS(alias,sym)						\
	.global alias;							\
	alias = sym
#define	WEAK_ALIAS(alias,sym)						\
	.weak alias;							\
	alias = sym

/* generic retpoline ("return trampoline") generator */
#define	JMP_RETPOLINE(reg)		\
		call	69f		; \
	68:	pause			; \
		lfence			; \
		jmp	68b		; \
		_ALIGN_TRAPS		; \
	69:	mov	%reg,(%rsp)	; \
		ret			; \
		lfence

#endif /* !_MACHINE_ASM_H_ */