1/*-
2 * Copyright (c) 2016 The FreeBSD Foundation
3 *
4 * This software was developed by Konstantin Belousov under sponsorship
5 * from the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29	.macro	EH	N, err=1
30	.align	8
31	.globl	EXC\N\()_handler
32EXC\N\()_handler:
33	.if	\err != 1
34	pushq	$0
35	.endif
36	pushq	%rax
37	pushq	%rdx
38	pushq	%rcx
39	movl	$\N,%ecx
40	jmp	all_handlers
41	.endm
42
43	.text
44	EH	0,0
45	EH	1,0
46	EH	2,0
47	EH	3,0
48	EH	4,0
49	EH	5,0
50	EH	6,0
51	EH	7,0
52	EH	8
53	EH	9,0
54	EH	10
55	EH	11
56	EH	12
57	EH	13
58	EH	14
59	EH	16,0
60	EH	17
61	EH	18,0
62	EH	19,0
63	EH	20,0
64
65	.globl	exc_rsp
66all_handlers:
67	cmpq	%rsp,exc_rsp(%rip)
68	je	exception
69
70	/*
71	 * Interrupt, not exception.
72	 * First, copy the hardware interrupt frame to the previous stack.
73	 * Our handler always has private IST stack.
74	 */
75	movq	(6*8)(%rsp),%rax	/* saved %rsp value, AKA old stack */
76	subq	(5*8),%rax
77	movq	(3*8)(%rsp),%rdx	/* copy %rip to old stack */
78	movq	%rdx,(%rax)
79	movq	(4*8)(%rsp),%rdx	/* copy %cs */
80	movq	%rdx,(1*8)(%rax)
81	movq	(5*8)(%rsp),%rdx	/* copy %rflags */
82	movq	%rdx,(2*8)(%rax)
83	movq	(6*8)(%rsp),%rdx	/* copy %rsp */
84	movq	%rdx,(3*8)(%rax)
85	movq	(7*8)(%rsp),%rdx	/* copy %ss */
86	movq	%rdx,(4*8)(%rax)
87
88	/*
89	 * Now simulate invocation of the original interrupt handler
90	 * with retq.  We switch stacks and execute retq from the old
91	 * stack since there is no free registers at the last moment.
92	 */
93	subq	$16,%rax
94	leaq	fw_intr_handlers(%rip),%rdx
95	movq	(%rdx,%rcx,8),%rdx /* push intr handler address on old stack */
96	movq	%rdx,8(%rax)
97	movq	(2*8)(%rsp),%rcx   /* saved %rax is put on top of old stack */
98	movq	%rcx,(%rax)
99	movq	(%rsp),%rcx
100	movq	8(%rsp),%rdx
101
102	movq	32(%rsp),%rsp	/* switch to old stack */
103	popq	%rax
104	retq
105
106exception:
107	/*
108	 * Form the struct trapframe on our IST stack.
109	 * Skip three words, which are currently busy with temporal
110	 * saves.
111	 */
112	pushq	%r15
113	pushq	%r14
114	pushq	%r13
115	pushq	%r12
116	pushq	%r11
117	pushq	%r10
118	pushq	%rbp
119	pushq	%rbx
120	pushq	$0	/* %rax	*/
121	pushq	%r9
122	pushq	%r8
123	pushq	$0	/* %rcx */
124	pushq	$0	/* %rdx	*/
125	pushq	%rsi
126	pushq	%rdi
127
128	/*
129	 * Move %rax, %rdx, %rcx values into the final location,
130	 * from the three words which were skipped above.
131	 */
132	movq	0x88(%rsp),%rax
133	movq	%rax,0x30(%rsp)	/* tf_rax */
134	movq	0x78(%rsp),%rax
135	movq	%rax,0x18(%rsp)	/* tf_rcx */
136	movq	0x80(%rsp),%rax
137	movq	%rax,0x10(%rsp)	/* tf_rdx */
138
139	/*
140	 * And fill the three words themself.
141	 */
142	movq	%cr2,%rax
143	movq	%rax,0x80(%rsp)	/* tf_addr */
144	movl	%ecx,0x78(%rsp)	/* tf_trapno */
145	movw	%ds,0x8e(%rsp)
146	movw	%es,0x8c(%rsp)
147	movw	%fs,0x7c(%rsp)
148	movw	%gs,0x7e(%rsp)
149	movw	$0,0x88(%rsp)	/* tf_flags */
150
151	/*
152	 * Call dump routine.
153	 */
154	movq	%rsp,%rdi
155	callq	report_exc
156
157	/*
158	 * Hang after reporting. Interrupts are already disabled.
159	 */
1601:
161	hlt
162	jmp	1b
163