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