1329462Skib/* -*- mode: asm -*- */
21817Sdg/*-
31817Sdg * Copyright (c) 1993 The Regents of the University of California.
41817Sdg * All rights reserved.
51817Sdg *
6329462Skib * Copyright (c) 2018 The FreeBSD Foundation
7329462Skib * All rights reserved.
8329462Skib *
9329462Skib * Portions of this software were developed by
10329462Skib * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
11329462Skib * the FreeBSD Foundation.
12329462Skib *
131817Sdg * Redistribution and use in source and binary forms, with or without
141817Sdg * modification, are permitted provided that the following conditions
151817Sdg * are met:
161817Sdg * 1. Redistributions of source code must retain the above copyright
171817Sdg *    notice, this list of conditions and the following disclaimer.
181817Sdg * 2. Redistributions in binary form must reproduce the above copyright
191817Sdg *    notice, this list of conditions and the following disclaimer in the
201817Sdg *    documentation and/or other materials provided with the distribution.
211817Sdg * 4. Neither the name of the University nor the names of its contributors
221817Sdg *    may be used to endorse or promote products derived from this software
231817Sdg *    without specific prior written permission.
241817Sdg *
251817Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261817Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271817Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281817Sdg * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291817Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301817Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311817Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321817Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331817Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341817Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351817Sdg * SUCH DAMAGE.
361817Sdg *
3750477Speter * $FreeBSD: stable/11/sys/amd64/include/asmacros.h 350978 2019-08-13 13:48:44Z kib $
381817Sdg */
391817Sdg
402579Sbde#ifndef _MACHINE_ASMACROS_H_
412579Sbde#define _MACHINE_ASMACROS_H_
422123Sjkh
4316029Speter#include <sys/cdefs.h>
442579Sbde
4518961Sbde/* XXX too much duplication in various asm*.h's. */
4613107Sbde
4725083Sjdp/*
48163726Sbde * CNAME is used to manage the relationship between symbol names in C
4925083Sjdp * and the equivalent assembly language names.  CNAME is given a name as
5025083Sjdp * it would be used in a C program.  It expands to the equivalent assembly
51163726Sbde * language name.
5225083Sjdp */
5325083Sjdp#define CNAME(csym)		csym
5425083Sjdp
55114349Speter#define ALIGN_DATA	.p2align 3	/* 8 byte alignment, zero filled */
5622636Sbde#ifdef GPROF
5725083Sjdp#define ALIGN_TEXT	.p2align 4,0x90	/* 16-byte alignment, nop filled */
5822636Sbde#else
59114349Speter#define ALIGN_TEXT	.p2align 4,0x90	/* 16-byte alignment, nop filled */
6022636Sbde#endif
6125083Sjdp#define SUPERALIGN_TEXT	.p2align 4,0x90	/* 16-byte alignment, nop filled */
62757Sdg
6325083Sjdp#define GEN_ENTRY(name)		ALIGN_TEXT; .globl CNAME(name); \
6446548Sbde				.type CNAME(name),@function; CNAME(name):
6513107Sbde#define NON_GPROF_ENTRY(name)	GEN_ENTRY(name)
6618961Sbde#define NON_GPROF_RET		.byte 0xc3	/* opcode for `ret' */
67757Sdg
68171914Sjkoshy#define	END(name)		.size name, . - name
69171914Sjkoshy
70757Sdg#ifdef GPROF
71757Sdg/*
7246548Sbde * __mcount is like [.]mcount except that doesn't require its caller to set
7313107Sbde * up a frame pointer.  It must be called before pushing anything onto the
7413107Sbde * stack.  gcc should eventually generate code to call __mcount in most
7513107Sbde * cases.  This would make -pg in combination with -fomit-frame-pointer
7613107Sbde * useful.  gcc has a configuration variable PROFILE_BEFORE_PROLOGUE to
7713107Sbde * allow profiling before setting up the frame pointer, but this is
7813107Sbde * inadequate for good handling of special cases, e.g., -fpic works best
7913107Sbde * with profiling after the prologue.
8013107Sbde *
8146548Sbde * [.]mexitcount is a new function to support non-statistical profiling if an
8218961Sbde * accurate clock is available.  For C sources, calls to it are generated
8318961Sbde * by the FreeBSD extension `-mprofiler-epilogue' to gcc.  It is best to
8446548Sbde * call [.]mexitcount at the end of a function like the MEXITCOUNT macro does,
8518961Sbde * but gcc currently generates calls to it at the start of the epilogue to
8618961Sbde * avoid problems with -fpic.
8713107Sbde *
8846548Sbde * [.]mcount and __mcount may clobber the call-used registers and %ef.
8946548Sbde * [.]mexitcount may clobber %ecx and %ef.
9013107Sbde *
9118961Sbde * Cross-jumping makes non-statistical profiling timing more complicated.
9246548Sbde * It is handled in many cases by calling [.]mexitcount before jumping.  It
9346548Sbde * is handled for conditional jumps using CROSSJUMP() and CROSSJUMP_LABEL().
9418961Sbde * It is handled for some fault-handling jumps by not sharing the exit
9518961Sbde * routine.
9613107Sbde *
9713107Sbde * ALTENTRY() must be before a corresponding ENTRY() so that it can jump to
9813107Sbde * the main entry point.  Note that alt entries are counted twice.  They
9913107Sbde * have to be counted as ordinary entries for gprof to get the call times
10013107Sbde * right for the ordinary entries.
10113107Sbde *
10213107Sbde * High local labels are used in macros to avoid clashes with local labels
10313107Sbde * in functions.
10413107Sbde *
10518961Sbde * Ordinary `ret' is used instead of a macro `RET' because there are a lot
10618961Sbde * of `ret's.  0xc3 is the opcode for `ret' (`#define ret ... ret' can't
10718961Sbde * be used because this file is sometimes preprocessed in traditional mode).
10818961Sbde * `ret' clobbers eflags but this doesn't matter.
109757Sdg */
11013107Sbde#define ALTENTRY(name)		GEN_ENTRY(name) ; MCOUNT ; MEXITCOUNT ; jmp 9f
11118961Sbde#define	CROSSJUMP(jtrue, label, jfalse) \
11218961Sbde	jfalse 8f; MEXITCOUNT; jmp __CONCAT(to,label); 8:
11318961Sbde#define CROSSJUMPTARGET(label) \
11418961Sbde	ALIGN_TEXT; __CONCAT(to,label): ; MCOUNT; jmp label
11513107Sbde#define ENTRY(name)		GEN_ENTRY(name) ; 9: ; MCOUNT
116122940Speter#define FAKE_MCOUNT(caller)	pushq caller ; call __mcount ; popq %rcx
11713107Sbde#define MCOUNT			call __mcount
11813107Sbde#define MCOUNT_LABEL(name)	GEN_ENTRY(name) ; nop ; ALIGN_TEXT
119163722Sbde#ifdef GUPROF
120163726Sbde#define MEXITCOUNT		call .mexitcount
12118961Sbde#define ret			MEXITCOUNT ; NON_GPROF_RET
122163722Sbde#else
123163722Sbde#define MEXITCOUNT
124163722Sbde#endif
12518961Sbde
12618961Sbde#else /* !GPROF */
127757Sdg/*
128757Sdg * ALTENTRY() has to align because it is before a corresponding ENTRY().
129757Sdg * ENTRY() has to align to because there may be no ALTENTRY() before it.
13013107Sbde * If there is a previous ALTENTRY() then the alignment code for ENTRY()
13113107Sbde * is empty.
132757Sdg */
13313107Sbde#define ALTENTRY(name)		GEN_ENTRY(name)
13418961Sbde#define	CROSSJUMP(jtrue, label, jfalse)	jtrue label
13518961Sbde#define	CROSSJUMPTARGET(label)
13613107Sbde#define ENTRY(name)		GEN_ENTRY(name)
13713107Sbde#define FAKE_MCOUNT(caller)
1381321Sdg#define MCOUNT
13913107Sbde#define MCOUNT_LABEL(name)
14013107Sbde#define MEXITCOUNT
14113107Sbde#endif /* GPROF */
142757Sdg
143274489Sscottl/*
144274489Sscottl * Convenience for adding frame pointers to hand-coded ASM.  Useful for
145274489Sscottl * DTrace, HWPMC, and KDB.
146274489Sscottl */
147274489Sscottl#define PUSH_FRAME_POINTER	\
148274489Sscottl	pushq	%rbp ;		\
149274489Sscottl	movq	%rsp, %rbp ;
150274489Sscottl#define POP_FRAME_POINTER	\
151274489Sscottl	popq	%rbp
152274489Sscottl
153122849Speter#ifdef LOCORE
154122849Speter/*
155329462Skib * Access per-CPU data.
156329462Skib */
157329462Skib#define	PCPU(member)	%gs:PC_ ## member
158329462Skib#define	PCPU_ADDR(member, reg)					\
159329462Skib	movq %gs:PC_PRVSPACE, reg ;				\
160329462Skib	addq $PC_ ## member, reg
161329462Skib
162329462Skib/*
163156699Speter * Convenience macro for declaring interrupt entry points.
164122849Speter */
165122849Speter#define	IDTVEC(name)	ALIGN_TEXT; .globl __CONCAT(X,name); \
166122849Speter			.type __CONCAT(X,name),@function; __CONCAT(X,name):
167122849Speter
168329462Skib	.macro	SAVE_SEGS
169329462Skib	movw	%fs,TF_FS(%rsp)
170329462Skib	movw	%gs,TF_GS(%rsp)
171329462Skib	movw	%es,TF_ES(%rsp)
172329462Skib	movw	%ds,TF_DS(%rsp)
173329462Skib	.endm
174153241Sjhb
175329462Skib	.macro	MOVE_STACKS qw
176329462Skib	.L.offset=0
177329462Skib	.rept	\qw
178329462Skib	movq	.L.offset(%rsp),%rdx
179329462Skib	movq	%rdx,.L.offset(%rax)
180329462Skib	.L.offset=.L.offset+8
181329462Skib	.endr
182329462Skib	.endm
183153241Sjhb
184329462Skib	.macro	PTI_UUENTRY has_err
185329462Skib	movq	PCPU(KCR3),%rax
186329462Skib	movq	%rax,%cr3
187329462Skib	movq	PCPU(RSP0),%rax
188335857Skib	subq	$PTI_SIZE - 8 * (1 - \has_err),%rax
189329462Skib	MOVE_STACKS	((PTI_SIZE / 8) - 1 + \has_err)
190329462Skib	movq	%rax,%rsp
191329462Skib	popq	%rdx
192329462Skib	popq	%rax
193329462Skib	.endm
194153241Sjhb
195329462Skib	.macro	PTI_UENTRY has_err
196329462Skib	swapgs
197350978Skib	lfence
198335570Skib	cmpq	$~0,PCPU(UCR3)
199335570Skib	je	1f
200329462Skib	pushq	%rax
201329462Skib	pushq	%rdx
202329462Skib	PTI_UUENTRY \has_err
203335570Skib1:
204329462Skib	.endm
205329462Skib
206350839Skib	.macro	PTI_ENTRY name, contk, contu, has_err=0
207329462Skib	ALIGN_TEXT
208329462Skib	.globl	X\name\()_pti
209329462Skib	.type	X\name\()_pti,@function
210329462SkibX\name\()_pti:
211350839Skib	/* %rax, %rdx, and possibly err are not yet pushed */
212350839Skib	testb	$SEL_RPL_MASK,PTI_CS-PTI_ERR-((1-\has_err)*8)(%rsp)
213350839Skib	jz	\contk
214329462Skib	PTI_UENTRY \has_err
215350839Skib	jmp	\contu
216329462Skib	.endm
217329462Skib
218329462Skib	.macro	PTI_INTRENTRY vec_name
219329462Skib	SUPERALIGN_TEXT
220329462Skib	.globl	X\vec_name\()_pti
221329462Skib	.type	X\vec_name\()_pti,@function
222329462SkibX\vec_name\()_pti:
223329462Skib	testb	$SEL_RPL_MASK,PTI_CS-3*8(%rsp) /* err, %rax, %rdx not pushed */
224334330Sjhb	jz	.L\vec_name\()_u
225329462Skib	PTI_UENTRY has_err=0
226334330Sjhb	jmp	.L\vec_name\()_u
227329462Skib	.endm
228329462Skib
229329462Skib	.macro	INTR_PUSH_FRAME vec_name
230329462Skib	SUPERALIGN_TEXT
231329462Skib	.globl	X\vec_name
232329462Skib	.type	X\vec_name,@function
233329462SkibX\vec_name:
234329462Skib	testb	$SEL_RPL_MASK,PTI_CS-3*8(%rsp) /* come from kernel? */
235334330Sjhb	jz	.L\vec_name\()_u		/* Yes, dont swapgs again */
236329462Skib	swapgs
237334330Sjhb.L\vec_name\()_u:
238350978Skib	lfence
239329462Skib	subq	$TF_RIP,%rsp	/* skip dummy tf_err and tf_trapno */
240329462Skib	movq	%rdi,TF_RDI(%rsp)
241329462Skib	movq	%rsi,TF_RSI(%rsp)
242329462Skib	movq	%rdx,TF_RDX(%rsp)
243329462Skib	movq	%rcx,TF_RCX(%rsp)
244329462Skib	movq	%r8,TF_R8(%rsp)
245329462Skib	movq	%r9,TF_R9(%rsp)
246329462Skib	movq	%rax,TF_RAX(%rsp)
247329462Skib	movq	%rbx,TF_RBX(%rsp)
248329462Skib	movq	%rbp,TF_RBP(%rsp)
249329462Skib	movq	%r10,TF_R10(%rsp)
250329462Skib	movq	%r11,TF_R11(%rsp)
251329462Skib	movq	%r12,TF_R12(%rsp)
252329462Skib	movq	%r13,TF_R13(%rsp)
253329462Skib	movq	%r14,TF_R14(%rsp)
254329462Skib	movq	%r15,TF_R15(%rsp)
255329462Skib	SAVE_SEGS
256329462Skib	movl	$TF_HASSEGS,TF_FLAGS(%rsp)
257329462Skib	cld
258329462Skib	testb	$SEL_RPL_MASK,TF_CS(%rsp)  /* come from kernel ? */
259329462Skib	jz	1f		/* yes, leave PCB_FULL_IRET alone */
260329462Skib	movq	PCPU(CURPCB),%r8
261329462Skib	andl	$~PCB_FULL_IRET,PCB_FLAGS(%r8)
262334327Skib	call	handle_ibrs_entry
263329462Skib1:
264329462Skib	.endm
265329462Skib
266329462Skib	.macro	INTR_HANDLER vec_name
267329462Skib	.text
268329462Skib	PTI_INTRENTRY	\vec_name
269329462Skib	INTR_PUSH_FRAME	\vec_name
270329462Skib	.endm
271329462Skib
272329462Skib	.macro	RESTORE_REGS
273329462Skib	movq	TF_RDI(%rsp),%rdi
274329462Skib	movq	TF_RSI(%rsp),%rsi
275329462Skib	movq	TF_RDX(%rsp),%rdx
276329462Skib	movq	TF_RCX(%rsp),%rcx
277329462Skib	movq	TF_R8(%rsp),%r8
278329462Skib	movq	TF_R9(%rsp),%r9
279329462Skib	movq	TF_RAX(%rsp),%rax
280329462Skib	movq	TF_RBX(%rsp),%rbx
281329462Skib	movq	TF_RBP(%rsp),%rbp
282329462Skib	movq	TF_R10(%rsp),%r10
283329462Skib	movq	TF_R11(%rsp),%r11
284329462Skib	movq	TF_R12(%rsp),%r12
285329462Skib	movq	TF_R13(%rsp),%r13
286329462Skib	movq	TF_R14(%rsp),%r14
287329462Skib	movq	TF_R15(%rsp),%r15
288329462Skib	.endm
289329462Skib
290122849Speter#endif /* LOCORE */
291122849Speter
292263002Sroyger#ifdef __STDC__
293263002Sroyger#define ELFNOTE(name, type, desctype, descdata...) \
294263002Sroyger.pushsection .note.name                 ;       \
295263002Sroyger  .align 4                              ;       \
296263002Sroyger  .long 2f - 1f         /* namesz */    ;       \
297263002Sroyger  .long 4f - 3f         /* descsz */    ;       \
298263002Sroyger  .long type                            ;       \
299263002Sroyger1:.asciz #name                          ;       \
300263002Sroyger2:.align 4                              ;       \
301263002Sroyger3:desctype descdata                     ;       \
302263002Sroyger4:.align 4                              ;       \
303263002Sroyger.popsection
304263002Sroyger#else /* !__STDC__, i.e. -traditional */
305263002Sroyger#define ELFNOTE(name, type, desctype, descdata) \
306263002Sroyger.pushsection .note.name                 ;       \
307263002Sroyger  .align 4                              ;       \
308263002Sroyger  .long 2f - 1f         /* namesz */    ;       \
309263002Sroyger  .long 4f - 3f         /* descsz */    ;       \
310263002Sroyger  .long type                            ;       \
311263002Sroyger1:.asciz "name"                         ;       \
312263002Sroyger2:.align 4                              ;       \
313263002Sroyger3:desctype descdata                     ;       \
314263002Sroyger4:.align 4                              ;       \
315263002Sroyger.popsection
316263002Sroyger#endif /* __STDC__ */
317263002Sroyger
3182579Sbde#endif /* !_MACHINE_ASMACROS_H_ */
319