1/*	$OpenBSD: frameasm.h,v 1.27 2023/07/27 00:30:07 guenther Exp $	*/
2/*	$NetBSD: frameasm.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $	*/
3
4#ifndef _AMD64_MACHINE_FRAMEASM_H
5#define _AMD64_MACHINE_FRAMEASM_H
6
7/*
8 * Macros to define pushing/popping frames for interrupts, traps
9 * and system calls. Currently all the same; will diverge later.
10 */
11
12/*
13 * These are used on interrupt or trap entry or exit.
14 */
15#define INTR_SAVE_GPRS \
16	subq	$120,%rsp		; \
17	INTR_SAVE_MOST_GPRS_NO_ADJ	; \
18	movq	%rcx,TF_RCX(%rsp)
19#define INTR_SAVE_MOST_GPRS_NO_ADJ \
20	movq	%r15,TF_R15(%rsp)	; \
21	movq	%r14,TF_R14(%rsp)	; \
22	movq	%r13,TF_R13(%rsp)	; \
23	movq	%r12,TF_R12(%rsp)	; \
24	movq	%r11,TF_R11(%rsp)	; \
25	movq	%r10,TF_R10(%rsp)	; \
26	movq	%r9,TF_R9(%rsp)		; \
27	movq	%r8,TF_R8(%rsp)		; \
28	movq	%rdi,TF_RDI(%rsp)	; \
29	movq	%rsi,TF_RSI(%rsp)	; \
30	movq	%rbp,TF_RBP(%rsp)	; \
31	leaq	TF_RBP(%rsp),%rbp	; \
32	movq	%rbx,TF_RBX(%rsp)	; \
33	movq	%rdx,TF_RDX(%rsp)	; \
34	movq	%rax,TF_RAX(%rsp)
35
36/*
37 * We clear registers when coming from userspace to prevent
38 * user-controlled values from being available for use in speculative
39 * execution in the kernel.  %rsp and %rbp are the kernel values when
40 * this is used, so there are only 14 to clear.  32bit operations clear
41 * the register upper-halves automatically.
42 */
43#define INTR_CLEAR_GPRS \
44	xorl	%eax,%eax		; \
45	xorl	%ebx,%ebx		; \
46	xorl	%ecx,%ecx		; \
47	xorl	%edx,%edx		; \
48	xorl	%esi,%esi		; \
49	xorl	%edi,%edi		; \
50	xorl	%r8d,%r8d		; \
51	xorl	%r9d,%r9d		; \
52	xorl	%r10d,%r10d		; \
53	xorl	%r11d,%r11d		; \
54	xorl	%r12d,%r12d		; \
55	xorl	%r13d,%r13d		; \
56	xorl	%r14d,%r14d		; \
57	xorl	%r15d,%r15d
58
59
60/*
61 * For real interrupt code paths, where we can come from userspace.
62 * We only have an iretq_frame on entry.
63 */
64#define INTRENTRY_LABEL(label)	X##label##_untramp
65#define	INTRENTRY(label) \
66	endbr64				; \
67	testb	$SEL_RPL,IRETQ_CS(%rsp)	; \
68	je	INTRENTRY_LABEL(label)	; \
69	swapgs				; \
70	FENCE_SWAPGS_MIS_TAKEN 		; \
71	movq	%rax,CPUVAR(SCRATCH)	; \
72	CODEPATCH_START			; \
73	movq	CPUVAR(KERN_CR3),%rax	; \
74	movq	%rax,%cr3		; \
75	CODEPATCH_END(CPTAG_MELTDOWN_NOP);\
76	jmp	98f			; \
77END(X##label)				; \
78_ENTRY(INTRENTRY_LABEL(label)) /* from kernel */ \
79	FENCE_NO_SAFE_SMAP		; \
80	subq	$TF_RIP,%rsp		; \
81	movq	%rcx,TF_RCX(%rsp)	; \
82	jmp	99f			; \
83	_ALIGN_TRAPS			; \
8498:	/* from userspace */		  \
85	movq	CPUVAR(KERN_RSP),%rax	; \
86	xchgq	%rax,%rsp		; \
87	movq	%rcx,TF_RCX(%rsp)	; \
88	RET_STACK_REFILL_WITH_RCX	; \
89	/* copy iretq frame to the trap frame */ \
90	movq	IRETQ_RIP(%rax),%rcx	; \
91	movq	%rcx,TF_RIP(%rsp)	; \
92	movq	IRETQ_CS(%rax),%rcx	; \
93	movq	%rcx,TF_CS(%rsp)	; \
94	movq	IRETQ_RFLAGS(%rax),%rcx	; \
95	movq	%rcx,TF_RFLAGS(%rsp)	; \
96	movq	IRETQ_RSP(%rax),%rcx	; \
97	movq	%rcx,TF_RSP(%rsp)	; \
98	movq	IRETQ_SS(%rax),%rcx	; \
99	movq	%rcx,TF_SS(%rsp)	; \
100	movq	CPUVAR(SCRATCH),%rax	; \
10199:	INTR_SAVE_MOST_GPRS_NO_ADJ	; \
102	INTR_CLEAR_GPRS			; \
103	movq	%rax,TF_ERR(%rsp)
104
105#define INTRFASTEXIT \
106	jmp	intr_fast_exit
107
108/*
109 * Entry for faking up an interrupt frame after spllower() unblocks
110 * a previously received interrupt.  On entry, %r13 has the %rip
111 * to return to.  %r10 and %r11 are scratch.
112 */
113#define	INTR_RECURSE \
114	endbr64				; \
115	/* fake the iretq_frame */	; \
116	movq	%rsp,%r10		; \
117	movl	%ss,%r11d		; \
118	pushq	%r11			; \
119	pushq	%r10			; \
120	pushfq				; \
121	movl	%cs,%r11d		; \
122	pushq	%r11			; \
123	pushq	%r13			; \
124	/* now do the rest of the intrframe */ \
125	subq	$16,%rsp		; \
126	INTR_SAVE_GPRS
127
128
129/*
130 * Entry for traps from kernel, where there's a trapno + err already
131 * on the stack.  We have to move the err from its hardware location
132 * to the location we want it.
133 */
134#define	TRAP_ENTRY_KERN \
135	subq	$120,%rsp		; \
136	movq	%rcx,TF_RCX(%rsp)	; \
137	movq	(TF_RIP - 8)(%rsp),%rcx	; \
138	movq	%rcx,TF_ERR(%rsp)	; \
139	INTR_SAVE_MOST_GPRS_NO_ADJ
140
141/*
142 * Entry for traps from userland, where there's a trapno + err on
143 * the iretq stack.
144 * Assumes that %rax has been saved in CPUVAR(SCRATCH).
145 */
146#define	TRAP_ENTRY_USER \
147	movq	CPUVAR(KERN_RSP),%rax		; \
148	xchgq	%rax,%rsp			; \
149	movq	%rcx,TF_RCX(%rsp)		; \
150	RET_STACK_REFILL_WITH_RCX		; \
151	/* copy trapno+err to the trap frame */ \
152	movq	0(%rax),%rcx			; \
153	movq	%rcx,TF_TRAPNO(%rsp)		; \
154	movq	8(%rax),%rcx			; \
155	movq	%rcx,TF_ERR(%rsp)		; \
156	/* copy iretq frame to the trap frame */ \
157	movq	(IRETQ_RIP+16)(%rax),%rcx	; \
158	movq	%rcx,TF_RIP(%rsp)		; \
159	movq	(IRETQ_CS+16)(%rax),%rcx	; \
160	movq	%rcx,TF_CS(%rsp)		; \
161	movq	(IRETQ_RFLAGS+16)(%rax),%rcx	; \
162	movq	%rcx,TF_RFLAGS(%rsp)		; \
163	movq	(IRETQ_RSP+16)(%rax),%rcx	; \
164	movq	%rcx,TF_RSP(%rsp)		; \
165	movq	(IRETQ_SS+16)(%rax),%rcx	; \
166	movq	%rcx,TF_SS(%rsp)		; \
167	movq	CPUVAR(SCRATCH),%rax		; \
168	INTR_SAVE_MOST_GPRS_NO_ADJ		; \
169	INTR_CLEAR_GPRS
170
171/*
172 * Entry from syscall instruction, where RIP is in %rcx and RFLAGS is in %r11.
173 * We stash the syscall # in tf_err for SPL check.
174 * Assumes that %rax has been saved in CPUVAR(SCRATCH).
175 */
176#define	SYSCALL_ENTRY \
177	movq	CPUVAR(KERN_RSP),%rax				; \
178	xchgq	%rax,%rsp					; \
179	movq	%rcx,TF_RCX(%rsp)				; \
180	movq	%rcx,TF_RIP(%rsp)				; \
181	RET_STACK_REFILL_WITH_RCX				; \
182	movq	$(GSEL(GUDATA_SEL, SEL_UPL)),TF_SS(%rsp)	; \
183	movq	%rax,TF_RSP(%rsp)				; \
184	movq	CPUVAR(SCRATCH),%rax				; \
185	INTR_SAVE_MOST_GPRS_NO_ADJ				; \
186	movq	%r11, TF_RFLAGS(%rsp)				; \
187	movq	$(GSEL(GUCODE_SEL, SEL_UPL)), TF_CS(%rsp)	; \
188	movq	%rax,TF_ERR(%rsp)				; \
189	INTR_CLEAR_GPRS
190
191#define CHECK_ASTPENDING(reg)	movq	CPUVAR(CURPROC),reg		; \
192				cmpq	$0, reg				; \
193				je	99f				; \
194				cmpl	$0, P_MD_ASTPENDING(reg)	; \
195				99:
196
197#define CLEAR_ASTPENDING(reg)	movl	$0, P_MD_ASTPENDING(reg)
198
199#endif /* _AMD64_MACHINE_FRAMEASM_H */
200