blob: dc2869b9ba745d8bcf4f3d3179eb7a9b54029940 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2015 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24#include <sys/types.h>
25#include <debug.h>
26#include <err.h>
27#include <reg.h>
28#include <kernel/thread.h>
29#include <platform/interrupts.h>
30#include <arch/ops.h>
31#include <arch/x86.h>
32#include <arch/fpu.h>
33#include <kernel/spinlock.h>
34#include "platform_p.h"
35#include <platform/pc.h>
36
37static spin_lock_t lock;
38
39void x86_gpf_handler(struct x86_iframe *frame);
40void x86_invop_handler(struct x86_iframe *frame);
41void x86_unhandled_exception(struct x86_iframe *frame);
42#ifdef ARCH_X86_64
43void x86_pfe_handler(struct x86_iframe *frame);
44#endif
45
46#define PIC1 0x20
47#define PIC2 0xA0
48
49#define ICW1 0x11
50#define ICW4 0x01
51
52struct int_handler_struct {
53 int_handler handler;
54 void *arg;
55};
56
57static struct int_handler_struct int_handler_table[INT_VECTORS];
58
59/*
60 * Cached IRQ mask (enabled/disabled)
61 */
62static uint8_t irqMask[2];
63
64/*
65 * init the PICs and remap them
66 */
67static void map(uint32_t pic1, uint32_t pic2)
68{
69 /* send ICW1 */
70 outp(PIC1, ICW1);
71 outp(PIC2, ICW1);
72
73 /* send ICW2 */
74 outp(PIC1 + 1, pic1); /* remap */
75 outp(PIC2 + 1, pic2); /* pics */
76
77 /* send ICW3 */
78 outp(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
79 outp(PIC2 + 1, 2);
80
81 /* send ICW4 */
82 outp(PIC1 + 1, 5);
83 outp(PIC2 + 1, 1);
84
85 /* disable all IRQs */
86 outp(PIC1 + 1, 0xff);
87 outp(PIC2 + 1, 0xff);
88
89 irqMask[0] = 0xff;
90 irqMask[1] = 0xff;
91}
92
93static void enable(unsigned int vector, bool enable)
94{
95 if (vector >= PIC1_BASE && vector < PIC1_BASE + 8) {
96 vector -= PIC1_BASE;
97
98 uint8_t bit = 1 << vector;
99
100 if (enable && (irqMask[0] & bit)) {
101 irqMask[0] = inp(PIC1 + 1);
102 irqMask[0] &= ~bit;
103 outp(PIC1 + 1, irqMask[0]);
104 irqMask[0] = inp(PIC1 + 1);
105 } else if (!enable && !(irqMask[0] & bit)) {
106 irqMask[0] = inp(PIC1 + 1);
107 irqMask[0] |= bit;
108 outp(PIC1 + 1, irqMask[0]);
109 irqMask[0] = inp(PIC1 + 1);
110 }
111 } else if (vector >= PIC2_BASE && vector < PIC2_BASE + 8) {
112 vector -= PIC2_BASE;
113
114 uint8_t bit = 1 << vector;
115
116 if (enable && (irqMask[1] & bit)) {
117 irqMask[1] = inp(PIC2 + 1);
118 irqMask[1] &= ~bit;
119 outp(PIC2 + 1, irqMask[1]);
120 irqMask[1] = inp(PIC2 + 1);
121 } else if (!enable && !(irqMask[1] & bit)) {
122 irqMask[1] = inp(PIC2 + 1);
123 irqMask[1] |= bit;
124 outp(PIC2 + 1, irqMask[1]);
125 irqMask[1] = inp(PIC2 + 1);
126 }
127
128 bit = 1 << (INT_PIC2 - PIC1_BASE);
129
130 if (irqMask[1] != 0xff && (irqMask[0] & bit)) {
131 irqMask[0] = inp(PIC1 + 1);
132 irqMask[0] &= ~bit;
133 outp(PIC1 + 1, irqMask[0]);
134 irqMask[0] = inp(PIC1 + 1);
135 } else if (irqMask[1] == 0 && !(irqMask[0] & bit)) {
136 irqMask[0] = inp(PIC1 + 1);
137 irqMask[0] |= bit;
138 outp(PIC1 + 1, irqMask[0]);
139 irqMask[0] = inp(PIC1 + 1);
140 }
141 } else {
142 //dprintf(DEBUG, "Invalid PIC interrupt: %02x\n", vector);
143 }
144}
145
146void issueEOI(unsigned int vector)
147{
148 if (vector >= PIC1_BASE && vector <= PIC1_BASE + 7) {
149 outp(PIC1, 0x20);
150 } else if (vector >= PIC2_BASE && vector <= PIC2_BASE + 7) {
151 outp(PIC2, 0x20);
152 outp(PIC1, 0x20); // must issue both for the second PIC
153 }
154}
155
156void platform_init_interrupts(void)
157{
158 // rebase the PIC out of the way of processor exceptions
159 map(PIC1_BASE, PIC2_BASE);
160}
161
162status_t mask_interrupt(unsigned int vector)
163{
164 if (vector >= INT_VECTORS)
165 return ERR_INVALID_ARGS;
166
167// dprintf(DEBUG, "%s: vector %d\n", __PRETTY_FUNCTION__, vector);
168
169 spin_lock_saved_state_t state;
170 spin_lock_irqsave(&lock, state);
171
172 enable(vector, false);
173
174 spin_unlock_irqrestore(&lock, state);
175
176 return NO_ERROR;
177}
178
179
180void platform_mask_irqs(void)
181{
182 irqMask[0] = inp(PIC1 + 1);
183 irqMask[1] = inp(PIC2 + 1);
184
185 outp(PIC1 + 1, 0xff);
186 outp(PIC2 + 1, 0xff);
187
188 irqMask[0] = inp(PIC1 + 1);
189 irqMask[1] = inp(PIC2 + 1);
190}
191
192status_t unmask_interrupt(unsigned int vector)
193{
194 if (vector >= INT_VECTORS)
195 return ERR_INVALID_ARGS;
196
197// dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
198
199 spin_lock_saved_state_t state;
200 spin_lock_irqsave(&lock, state);
201
202 enable(vector, true);
203
204 spin_unlock_irqrestore(&lock, state);
205
206 return NO_ERROR;
207}
208
209enum handler_return platform_irq(struct x86_iframe *frame)
210{
211 // get the current vector
212 unsigned int vector = frame->vector;
213
214 THREAD_STATS_INC(interrupts);
215
216 // deliver the interrupt
217 enum handler_return ret = INT_NO_RESCHEDULE;
218
219 switch (vector) {
220 case INT_GP_FAULT:
221 x86_gpf_handler(frame);
222 break;
223
224 case INT_INVALID_OP:
225 x86_invop_handler(frame);
226 break;
227 case INT_PAGE_FAULT:
228#ifdef ARCH_X86_64
229 x86_pfe_handler(frame);
230#endif
231 break;
232
233 case INT_DEV_NA_EX:
234#if X86_WITH_FPU
235 fpu_dev_na_handler();
236 break;
237#endif
238
239 case INT_MF:
240 case INT_XM:
241 case INT_DIVIDE_0:
242 case INT_DEBUG_EX:
243 case INT_STACK_FAULT:
244 case 3:
245 x86_unhandled_exception(frame);
246 break;
247
248 default:
249 if (int_handler_table[vector].handler)
250 ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
251 }
252
253 // ack the interrupt
254 issueEOI(vector);
255
256 return ret;
257}
258
259void register_int_handler(unsigned int vector, int_handler handler, void *arg)
260{
261 if (vector >= INT_VECTORS)
262 panic("register_int_handler: vector out of range %d\n", vector);
263
264 spin_lock_saved_state_t state;
265 spin_lock_irqsave(&lock, state);
266
267 int_handler_table[vector].arg = arg;
268 int_handler_table[vector].handler = handler;
269
270 spin_unlock_irqrestore(&lock, state);
271}
272
273/* vim: set noexpandtab: */
274