summaryrefslogtreecommitdiff
path: root/sys/arch/amd64/include/frameasm.h
blob: 33ab8b4b347d5f7825f502d3d8b4ae7bf9060d03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*	$OpenBSD: frameasm.h,v 1.19 2018/07/21 02:19:54 guenther Exp $	*/
/*	$NetBSD: frameasm.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $	*/

#ifndef _AMD64_MACHINE_FRAMEASM_H
#define _AMD64_MACHINE_FRAMEASM_H

/*
 * Macros to define pushing/popping frames for interrupts, traps
 * and system calls. Currently all the same; will diverge later.
 */

/*
 * These are used on interrupt or trap entry or exit.
 */
#define INTR_SAVE_GPRS \
	subq	$120,%rsp		; \
	INTR_SAVE_MOST_GPRS_NO_ADJ	; \
	movq	%rcx,TF_RCX(%rsp)
#define INTR_SAVE_MOST_GPRS_NO_ADJ \
	movq	%r15,TF_R15(%rsp)	; \
	movq	%r14,TF_R14(%rsp)	; \
	movq	%r13,TF_R13(%rsp)	; \
	movq	%r12,TF_R12(%rsp)	; \
	movq	%r11,TF_R11(%rsp)	; \
	movq	%r10,TF_R10(%rsp)	; \
	movq	%r9,TF_R9(%rsp)		; \
	movq	%r8,TF_R8(%rsp)		; \
	movq	%rdi,TF_RDI(%rsp)	; \
	movq	%rsi,TF_RSI(%rsp)	; \
	movq	%rbp,TF_RBP(%rsp)	; \
	leaq	TF_RBP(%rsp),%rbp	; \
	movq	%rbx,TF_RBX(%rsp)	; \
	movq	%rdx,TF_RDX(%rsp)	; \
	movq	%rax,TF_RAX(%rsp)

/*
 * We clear registers when coming from userspace to prevent
 * user-controlled values from being availible for use in speculative
 * execution in the kernel.  %rsp and %rbp are the kernel values when
 * this is used, so there are only 14 to clear.  32bit operations clear
 * the register upper-halves automatically.
 */
#define INTR_CLEAR_GPRS \
	xorl	%eax,%eax		; \
	xorl	%ebx,%ebx		; \
	xorl	%ecx,%ecx		; \
	xorl	%edx,%edx		; \
	xorl	%esi,%esi		; \
	xorl	%edi,%edi		; \
	xorl	%r8d,%r8d		; \
	xorl	%r9d,%r9d		; \
	xorl	%r10d,%r10d		; \
	xorl	%r11d,%r11d		; \
	xorl	%r12d,%r12d		; \
	xorl	%r13d,%r13d		; \
	xorl	%r14d,%r14d		; \
	xorl	%r15d,%r15d


/* For real interrupt code paths, where we can come from userspace */
#define INTRENTRY_LABEL(label)	X##label##_untramp
#define	INTRENTRY(label) \
	testb	$SEL_RPL,24(%rsp)	; \
	je	INTRENTRY_LABEL(label)	; \
	swapgs				; \
	movq	%rax,CPUVAR(SCRATCH)	; \
	CODEPATCH_START			; \
	movq	CPUVAR(KERN_CR3),%rax	; \
	movq	%rax,%cr3		; \
	CODEPATCH_END(CPTAG_MELTDOWN_NOP);\
	jmp	98f			; \
	.text				; \
	_ALIGN_TRAPS			; \
	.global	INTRENTRY_LABEL(label)	; \
INTRENTRY_LABEL(label):	/* from kernel */ \
	INTR_ENTRY_KERN			; \
	jmp	99f			; \
	_ALIGN_TRAPS			; \
98:	/* from userspace */		  \
	INTR_ENTRY_USER			; \
99:	INTR_SAVE_MOST_GPRS_NO_ADJ	; \
	INTR_CLEAR_GPRS

#define	INTR_ENTRY_KERN \
	subq	$120,%rsp		; \
	movq	%rcx,TF_RCX(%rsp)	; \
	/* the hardware puts err next to %rip, we move it elsewhere and */ \
	/* later put %rbp in this slot to make it look like a call frame */ \
	movq	(TF_RIP - 8)(%rsp),%rcx	; \
	movq	%rcx,TF_ERR(%rsp)

#define	INTR_ENTRY_USER \
	movq	CPUVAR(KERN_RSP),%rax	; \
	xchgq	%rax,%rsp		; \
	movq	%rcx,TF_RCX(%rsp)	; \
	/* copy trapno+err to the trap frame */ \
	movq	0(%rax),%rcx		; \
	movq	%rcx,TF_TRAPNO(%rsp)	; \
	movq	8(%rax),%rcx		; \
	movq	%rcx,TF_ERR(%rsp)	; \
	addq	$16,%rax		; \
	/* copy iretq frame to the trap frame */ \
	movq	IRETQ_RIP(%rax),%rcx	; \
	movq	%rcx,TF_RIP(%rsp)	; \
	movq	IRETQ_CS(%rax),%rcx	; \
	movq	%rcx,TF_CS(%rsp)	; \
	movq	IRETQ_RFLAGS(%rax),%rcx	; \
	movq	%rcx,TF_RFLAGS(%rsp)	; \
	movq	IRETQ_RSP(%rax),%rcx	; \
	movq	%rcx,TF_RSP(%rsp)	; \
	movq	IRETQ_SS(%rax),%rcx	; \
	movq	%rcx,TF_SS(%rsp)	; \
	movq	CPUVAR(SCRATCH),%rax

/* For faking up an interrupt frame when we're already in the kernel */
#define	INTR_REENTRY \
	INTR_SAVE_GPRS

#define INTRFASTEXIT \
	jmp	intr_fast_exit

#define INTR_RECURSE_HWFRAME \
	movq	%rsp,%r10		; \
	movl	%ss,%r11d		; \
	pushq	%r11			; \
	pushq	%r10			; \
	pushfq				; \
	movl	%cs,%r11d		; \
	pushq	%r11			; \
	pushq	%r13			;

#define CHECK_ASTPENDING(reg)	movq	CPUVAR(CURPROC),reg		; \
				cmpq	$0, reg				; \
				je	99f				; \
				cmpl	$0, P_MD_ASTPENDING(reg)	; \
				99:

#define CLEAR_ASTPENDING(reg)	movl	$0, P_MD_ASTPENDING(reg)

#endif /* _AMD64_MACHINE_FRAMEASM_H */