1
2 #include "irq.h"
3 #include <common/errno.h>
4
5 #if _INTR_8259A_
6 #include <driver/interrupt/8259A/8259A.h>
7 #else
8 #include <driver/interrupt/apic/apic.h>
9 #endif
10
11 #include "gate.h"
12 #include <common/asm.h>
13 #include <common/printk.h>
14 #include <common/string.h>
15 #include <mm/slab.h>
16 extern void ignore_int();
17
18 #pragma GCC push_options
19 #pragma GCC optimize("O0")
20 // 保存函数调用现场的寄存器
21 #define SAVE_ALL_REGS \
22 "cld; \n\t" \
23 "pushq %rax; \n\t" \
24 "pushq %rax; \n\t" \
25 "movq %es, %rax; \n\t" \
26 "pushq %rax; \n\t" \
27 "movq %ds, %rax; \n\t" \
28 "pushq %rax; \n\t" \
29 "xorq %rax, %rax;\n\t" \
30 "pushq %rbp; \n\t" \
31 "pushq %rdi; \n\t" \
32 "pushq %rsi; \n\t" \
33 "pushq %rdx; \n\t" \
34 "pushq %rcx; \n\t" \
35 "pushq %rbx; \n\t" \
36 "pushq %r8 ; \n\t" \
37 "pushq %r9 ; \n\t" \
38 "pushq %r10; \n\t" \
39 "pushq %r11; \n\t" \
40 "pushq %r12; \n\t" \
41 "pushq %r13; \n\t" \
42 "pushq %r14; \n\t" \
43 "pushq %r15; \n\t" \
44 "movq $0x10, %rdx;\n\t" \
45 "movq %rdx, %ds; \n\t" \
46 "movq %rdx, %es; \n\t"
47
48 // 定义IRQ处理函数的名字格式:IRQ+中断号+interrupt
49 #define IRQ_NAME2(name1) name1##interrupt(void)
50 #define IRQ_NAME(number) IRQ_NAME2(IRQ##number)
51
52 // 构造中断entry
53 // 为了复用返回函数的代码,需要压入一个错误码0
54 // todo: 将这里改为volatile,也许能解决编译选项为O1时,系统崩溃的问题
55 #define Build_IRQ(number) \
56 void IRQ_NAME(number); \
57 __asm__(SYMBOL_NAME_STR(IRQ) #number "interrupt: \n\t" \
58 "pushq $0x00 \n\t" SAVE_ALL_REGS "movq %rsp, %rdi \n\t" \
59 "leaq ret_from_intr(%rip), %rax \n\t" \
60 "pushq %rax \n\t" \
61 "movq $" #number ", %rsi \n\t" \
62 "jmp do_IRQ \n\t");
63
64 // 构造中断入口
65 Build_IRQ(0x20);
66 Build_IRQ(0x21);
67 Build_IRQ(0x22);
68 Build_IRQ(0x23);
69 Build_IRQ(0x24);
70 Build_IRQ(0x25);
71 Build_IRQ(0x26);
72 Build_IRQ(0x27);
73 Build_IRQ(0x28);
74 Build_IRQ(0x29);
75 Build_IRQ(0x2a);
76 Build_IRQ(0x2b);
77 Build_IRQ(0x2c);
78 Build_IRQ(0x2d);
79 Build_IRQ(0x2e);
80 Build_IRQ(0x2f);
81 Build_IRQ(0x30);
82 Build_IRQ(0x31);
83 Build_IRQ(0x32);
84 Build_IRQ(0x33);
85 Build_IRQ(0x34);
86 Build_IRQ(0x35);
87 Build_IRQ(0x36);
88 Build_IRQ(0x37);
89
90 // 初始化中断数组
91 void (*interrupt_table[24])(void) = {
92 IRQ0x20interrupt,
93 IRQ0x21interrupt,
94 IRQ0x22interrupt,
95 IRQ0x23interrupt,
96 IRQ0x24interrupt,
97 IRQ0x25interrupt,
98 IRQ0x26interrupt,
99 IRQ0x27interrupt,
100 IRQ0x28interrupt,
101 IRQ0x29interrupt,
102 IRQ0x2ainterrupt,
103 IRQ0x2binterrupt,
104 IRQ0x2cinterrupt,
105 IRQ0x2dinterrupt,
106 IRQ0x2einterrupt,
107 IRQ0x2finterrupt,
108 IRQ0x30interrupt,
109 IRQ0x31interrupt,
110 IRQ0x32interrupt,
111 IRQ0x33interrupt,
112 IRQ0x34interrupt,
113 IRQ0x35interrupt,
114 IRQ0x36interrupt,
115 IRQ0x37interrupt,
116 };
117
118 /**
119 * @brief 声明10个IPI消息处理程序,向量号从200(0xc8)开始
120 *
121 */
122
123 /*
124 */
125 Build_IRQ(0xc8);
126 Build_IRQ(0xc9);
127 Build_IRQ(0xca);
128 Build_IRQ(0xcb);
129 Build_IRQ(0xcc);
130 Build_IRQ(0xcd);
131 Build_IRQ(0xce);
132 Build_IRQ(0xcf);
133 Build_IRQ(0xd0);
134 Build_IRQ(0xd1);
135
136 Build_IRQ(0x80); // 系统调用入口
137 void (*syscall_intr_table[1])(void) = {IRQ0x80interrupt};
138
139 // 初始化IPI中断服务程序数组
140 void (*SMP_interrupt_table[SMP_IRQ_NUM])(void) = {
141 IRQ0xc8interrupt,
142 IRQ0xc9interrupt,
143 IRQ0xcainterrupt,
144 IRQ0xcbinterrupt,
145 IRQ0xccinterrupt,
146 IRQ0xcdinterrupt,
147 IRQ0xceinterrupt,
148 IRQ0xcfinterrupt,
149 IRQ0xd0interrupt,
150 IRQ0xd1interrupt,
151 };
152
153 // 初始化local apic中断服务程序数组
154 Build_IRQ(0x96);
155 Build_IRQ(0x97);
156 Build_IRQ(0x98);
157 Build_IRQ(0x99);
158 Build_IRQ(0x9a);
159 Build_IRQ(0x9b);
160 Build_IRQ(0x9c);
161 Build_IRQ(0x9d);
162 Build_IRQ(0x9e);
163 Build_IRQ(0x9f);
164 void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void) = {
165 IRQ0x96interrupt,
166 IRQ0x97interrupt,
167 IRQ0x98interrupt,
168 IRQ0x99interrupt,
169 IRQ0x9ainterrupt,
170 IRQ0x9binterrupt,
171 IRQ0x9cinterrupt,
172 IRQ0x9dinterrupt,
173 IRQ0x9einterrupt,
174 IRQ0x9finterrupt,
175 };
176
177 /**
178 * @brief 中断注册函数
179 *
180 * @param irq_num 中断向量号
181 * @param arg 传递给中断安装接口的参数
182 * @param handler 中断处理函数
183 * @param paramater 中断处理函数的参数
184 * @param controller 中断控制器结构
185 * @param irq_name 中断名
186 * @return int
187 */
irq_register(ul irq_num,void * arg,void (* handler)(ul irq_num,ul parameter,struct pt_regs * regs),ul paramater,hardware_intr_controller * controller,char * irq_name)188 int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater,
189 hardware_intr_controller *controller, char *irq_name)
190 {
191 // 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素
192 irq_desc_t *p = NULL;
193 if (irq_num >= 32 && irq_num < 0x80)
194 p = &interrupt_desc[irq_num - 32];
195 else if (irq_num >= 150 && irq_num < 200)
196 p = &local_apic_interrupt_desc[irq_num - 150];
197 else
198 {
199 kerror("irq_register(): invalid irq num: %ld.", irq_num);
200 return -EINVAL;
201 }
202 p->controller = controller;
203 if (p->irq_name == NULL)
204 {
205 int namelen = sizeof(strlen(irq_name) + 1);
206 p->irq_name = (char *)kmalloc(namelen, 0);
207 memset(p->irq_name, 0, namelen);
208 strncpy(p->irq_name, irq_name, namelen);
209 }
210
211 p->parameter = paramater;
212 p->flags = 0;
213 p->handler = handler;
214 io_mfence();
215 p->controller->install(irq_num, arg);
216 io_mfence();
217 p->controller->enable(irq_num);
218 io_mfence();
219
220 return 0;
221 }
222
223 /**
224 * @brief 中断注销函数
225 *
226 * @param irq_num 中断向量号
227 * @return int
228 */
irq_unregister(ul irq_num)229 int irq_unregister(ul irq_num)
230 {
231 irq_desc_t *p = &interrupt_desc[irq_num - 32];
232 p->controller->disable(irq_num);
233 p->controller->uninstall(irq_num);
234
235 p->controller = NULL;
236 if (p->irq_name)
237 kfree(p->irq_name);
238 p->irq_name = NULL;
239 p->parameter = NULL;
240 p->flags = 0;
241 p->handler = NULL;
242
243 return 0;
244 }
245
246 /**
247 * @brief 初始化中断模块
248 */
irq_init()249 void irq_init()
250 {
251 #if _INTR_8259A_
252 init_8259A();
253 #else
254
255 memset((void *)interrupt_desc, 0, sizeof(irq_desc_t) * IRQ_NUM);
256 apic_init();
257
258 #endif
259 }
260 #pragma GCC optimize("O0")
261