1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <common.h>
15#include <dm.h>
16#include <asm/control_regs.h>
17#include <asm/i8259.h>
18#include <asm/interrupt.h>
19#include <asm/io.h>
20#include <asm/lapic.h>
21#include <asm/processor-flags.h>
22
23DECLARE_GLOBAL_DATA_PTR;
24
25#define DECLARE_INTERRUPT(x) \
26 ".globl irq_"#x"\n" \
27 ".hidden irq_"#x"\n" \
28 ".type irq_"#x", @function\n" \
29 "irq_"#x":\n" \
30 "pushl $"#x"\n" \
31 "jmp.d32 irq_common_entry\n"
32
33static char *exceptions[] = {
34 "Divide Error",
35 "Debug",
36 "NMI Interrupt",
37 "Breakpoint",
38 "Overflow",
39 "BOUND Range Exceeded",
40 "Invalid Opcode (Undefined Opcode)",
41 "Device Not Avaiable (No Math Coprocessor)",
42 "Double Fault",
43 "Coprocessor Segment Overrun",
44 "Invalid TSS",
45 "Segment Not Present",
46 "Stack Segment Fault",
47 "General Protection",
48 "Page Fault",
49 "Reserved",
50 "x87 FPU Floating-Point Error",
51 "Alignment Check",
52 "Machine Check",
53 "SIMD Floating-Point Exception",
54 "Virtualization Exception",
55 "Reserved",
56 "Reserved",
57 "Reserved",
58 "Reserved",
59 "Reserved",
60 "Reserved",
61 "Reserved",
62 "Reserved",
63 "Reserved",
64 "Reserved",
65 "Reserved"
66};
67
68static void dump_regs(struct irq_regs *regs)
69{
70 unsigned long cs, eip, eflags;
71 unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
72 unsigned long d0, d1, d2, d3, d6, d7;
73 unsigned long sp;
74
75
76
77
78
79
80 switch (regs->irq_id) {
81 case EXC_DF:
82 case EXC_TS:
83 case EXC_NP:
84 case EXC_SS:
85 case EXC_GP:
86 case EXC_PF:
87 case EXC_AC:
88 cs = regs->context.ctx2.xcs;
89 eip = regs->context.ctx2.eip;
90 eflags = regs->context.ctx2.eflags;
91
92 regs->esp += 4;
93 break;
94 default:
95 cs = regs->context.ctx1.xcs;
96 eip = regs->context.ctx1.eip;
97 eflags = regs->context.ctx1.eflags;
98 break;
99 }
100
101 printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n",
102 (u16)cs, eip, eflags);
103 if (gd->flags & GD_FLG_RELOC)
104 printf("Original EIP :[<%08lx>]\n", eip - gd->reloc_off);
105
106 printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
107 regs->eax, regs->ebx, regs->ecx, regs->edx);
108 printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n",
109 regs->esi, regs->edi, regs->ebp, regs->esp);
110 printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n",
111 (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs,
112 (u16)regs->xgs, (u16)regs->xss);
113
114 cr0 = read_cr0();
115 cr2 = read_cr2();
116 cr3 = read_cr3();
117 cr4 = read_cr4();
118
119 printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
120 cr0, cr2, cr3, cr4);
121
122 d0 = get_debugreg(0);
123 d1 = get_debugreg(1);
124 d2 = get_debugreg(2);
125 d3 = get_debugreg(3);
126
127 printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
128 d0, d1, d2, d3);
129
130 d6 = get_debugreg(6);
131 d7 = get_debugreg(7);
132 printf("DR6: %08lx DR7: %08lx\n",
133 d6, d7);
134
135 printf("Stack:\n");
136 sp = regs->esp;
137
138 sp += 64;
139
140 while (sp > (regs->esp - 16)) {
141 if (sp == regs->esp)
142 printf("--->");
143 else
144 printf(" ");
145 printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp));
146 sp -= 4;
147 }
148}
149
150static void do_exception(struct irq_regs *regs)
151{
152 printf("%s\n", exceptions[regs->irq_id]);
153 dump_regs(regs);
154 hang();
155}
156
157struct idt_entry {
158 u16 base_low;
159 u16 selector;
160 u8 res;
161 u8 access;
162 u16 base_high;
163} __packed;
164
165struct desc_ptr {
166 unsigned short size;
167 unsigned long address;
168} __packed;
169
170struct idt_entry idt[256] __aligned(16);
171
172struct desc_ptr idt_ptr;
173
174static inline void load_idt(const struct desc_ptr *dtr)
175{
176 asm volatile("cs lidt %0" : : "m" (*dtr));
177}
178
179void set_vector(u8 intnum, void *routine)
180{
181 idt[intnum].base_high = (u16)((ulong)(routine) >> 16);
182 idt[intnum].base_low = (u16)((ulong)(routine) & 0xffff);
183}
184
185
186
187
188
189
190void irq_0(void);
191void irq_1(void);
192
193int cpu_init_interrupts(void)
194{
195 int i;
196
197 int irq_entry_size = irq_1 - irq_0;
198 void *irq_entry = (void *)irq_0;
199
200
201 for (i = 0; i < 256; i++) {
202 idt[i].access = 0x8e;
203 idt[i].res = 0;
204 idt[i].selector = X86_GDT_ENTRY_32BIT_CS * X86_GDT_ENTRY_SIZE;
205 set_vector(i, irq_entry);
206 irq_entry += irq_entry_size;
207 }
208
209 idt_ptr.size = 256 * 8 - 1;
210 idt_ptr.address = (unsigned long) idt;
211
212 load_idt(&idt_ptr);
213
214 return 0;
215}
216
217void *x86_get_idt(void)
218{
219 return &idt_ptr;
220}
221
222void __do_irq(int irq)
223{
224 printf("Unhandled IRQ : %d\n", irq);
225}
226void do_irq(int irq) __attribute__((weak, alias("__do_irq")));
227
228void enable_interrupts(void)
229{
230 asm("sti\n");
231}
232
233int disable_interrupts(void)
234{
235 long flags;
236
237#if CONFIG_IS_ENABLED(X86_64)
238 asm volatile ("pushfq ; popq %0 ; cli\n" : "=g" (flags) : );
239#else
240 asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : );
241#endif
242 return flags & X86_EFLAGS_IF;
243}
244
245int interrupt_init(void)
246{
247 struct udevice *dev;
248 int ret;
249
250
251 ret = uclass_first_device_err(UCLASS_IRQ, &dev);
252 if (ret && ret != -ENODEV)
253 return ret;
254
255
256
257
258
259#ifndef CONFIG_EFI_APP
260
261 disable_interrupts();
262
263#ifdef CONFIG_I8259_PIC
264
265 i8259_init();
266#endif
267
268 lapic_setup();
269
270
271 cpu_init_interrupts();
272
273
274
275
276
277
278
279 if (ll_boot_init())
280 enable_interrupts();
281#endif
282
283 return 0;
284}
285
286
287void irq_llsr(struct irq_regs *regs)
288{
289
290
291
292
293
294
295
296 if (regs->irq_id < 32) {
297
298 do_exception(regs);
299 } else {
300
301 do_irq(regs->irq_id);
302 }
303}
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323asm(".globl irq_common_entry\n" \
324 ".hidden irq_common_entry\n" \
325 ".type irq_common_entry, @function\n" \
326 "irq_common_entry:\n" \
327 "cld\n" \
328 "pushl %ss\n" \
329 "pushl %gs\n" \
330 "pushl %fs\n" \
331 "pushl %es\n" \
332 "pushl %ds\n" \
333 "pushl %eax\n" \
334 "movl %esp, %eax\n" \
335 "addl $40, %eax\n" \
336 "pushl %eax\n" \
337 "pushl %ebp\n" \
338 "pushl %edi\n" \
339 "pushl %esi\n" \
340 "pushl %edx\n" \
341 "pushl %ecx\n" \
342 "pushl %ebx\n" \
343 "mov %esp, %eax\n" \
344 "call irq_llsr\n" \
345 "popl %ebx\n" \
346 "popl %ecx\n" \
347 "popl %edx\n" \
348 "popl %esi\n" \
349 "popl %edi\n" \
350 "popl %ebp\n" \
351 "popl %eax\n" \
352 "popl %eax\n" \
353 "popl %ds\n" \
354 "popl %es\n" \
355 "popl %fs\n" \
356 "popl %gs\n" \
357 "popl %ss\n" \
358 "add $4, %esp\n" \
359 "iret\n" \
360 DECLARE_INTERRUPT(0) \
361 DECLARE_INTERRUPT(1) \
362 DECLARE_INTERRUPT(2) \
363 DECLARE_INTERRUPT(3) \
364 DECLARE_INTERRUPT(4) \
365 DECLARE_INTERRUPT(5) \
366 DECLARE_INTERRUPT(6) \
367 DECLARE_INTERRUPT(7) \
368 DECLARE_INTERRUPT(8) \
369 DECLARE_INTERRUPT(9) \
370 DECLARE_INTERRUPT(10) \
371 DECLARE_INTERRUPT(11) \
372 DECLARE_INTERRUPT(12) \
373 DECLARE_INTERRUPT(13) \
374 DECLARE_INTERRUPT(14) \
375 DECLARE_INTERRUPT(15) \
376 DECLARE_INTERRUPT(16) \
377 DECLARE_INTERRUPT(17) \
378 DECLARE_INTERRUPT(18) \
379 DECLARE_INTERRUPT(19) \
380 DECLARE_INTERRUPT(20) \
381 DECLARE_INTERRUPT(21) \
382 DECLARE_INTERRUPT(22) \
383 DECLARE_INTERRUPT(23) \
384 DECLARE_INTERRUPT(24) \
385 DECLARE_INTERRUPT(25) \
386 DECLARE_INTERRUPT(26) \
387 DECLARE_INTERRUPT(27) \
388 DECLARE_INTERRUPT(28) \
389 DECLARE_INTERRUPT(29) \
390 DECLARE_INTERRUPT(30) \
391 DECLARE_INTERRUPT(31) \
392 DECLARE_INTERRUPT(32) \
393 DECLARE_INTERRUPT(33) \
394 DECLARE_INTERRUPT(34) \
395 DECLARE_INTERRUPT(35) \
396 DECLARE_INTERRUPT(36) \
397 DECLARE_INTERRUPT(37) \
398 DECLARE_INTERRUPT(38) \
399 DECLARE_INTERRUPT(39) \
400 DECLARE_INTERRUPT(40) \
401 DECLARE_INTERRUPT(41) \
402 DECLARE_INTERRUPT(42) \
403 DECLARE_INTERRUPT(43) \
404 DECLARE_INTERRUPT(44) \
405 DECLARE_INTERRUPT(45) \
406 DECLARE_INTERRUPT(46) \
407 DECLARE_INTERRUPT(47) \
408 DECLARE_INTERRUPT(48) \
409 DECLARE_INTERRUPT(49) \
410 DECLARE_INTERRUPT(50) \
411 DECLARE_INTERRUPT(51) \
412 DECLARE_INTERRUPT(52) \
413 DECLARE_INTERRUPT(53) \
414 DECLARE_INTERRUPT(54) \
415 DECLARE_INTERRUPT(55) \
416 DECLARE_INTERRUPT(56) \
417 DECLARE_INTERRUPT(57) \
418 DECLARE_INTERRUPT(58) \
419 DECLARE_INTERRUPT(59) \
420 DECLARE_INTERRUPT(60) \
421 DECLARE_INTERRUPT(61) \
422 DECLARE_INTERRUPT(62) \
423 DECLARE_INTERRUPT(63) \
424 DECLARE_INTERRUPT(64) \
425 DECLARE_INTERRUPT(65) \
426 DECLARE_INTERRUPT(66) \
427 DECLARE_INTERRUPT(67) \
428 DECLARE_INTERRUPT(68) \
429 DECLARE_INTERRUPT(69) \
430 DECLARE_INTERRUPT(70) \
431 DECLARE_INTERRUPT(71) \
432 DECLARE_INTERRUPT(72) \
433 DECLARE_INTERRUPT(73) \
434 DECLARE_INTERRUPT(74) \
435 DECLARE_INTERRUPT(75) \
436 DECLARE_INTERRUPT(76) \
437 DECLARE_INTERRUPT(77) \
438 DECLARE_INTERRUPT(78) \
439 DECLARE_INTERRUPT(79) \
440 DECLARE_INTERRUPT(80) \
441 DECLARE_INTERRUPT(81) \
442 DECLARE_INTERRUPT(82) \
443 DECLARE_INTERRUPT(83) \
444 DECLARE_INTERRUPT(84) \
445 DECLARE_INTERRUPT(85) \
446 DECLARE_INTERRUPT(86) \
447 DECLARE_INTERRUPT(87) \
448 DECLARE_INTERRUPT(88) \
449 DECLARE_INTERRUPT(89) \
450 DECLARE_INTERRUPT(90) \
451 DECLARE_INTERRUPT(91) \
452 DECLARE_INTERRUPT(92) \
453 DECLARE_INTERRUPT(93) \
454 DECLARE_INTERRUPT(94) \
455 DECLARE_INTERRUPT(95) \
456 DECLARE_INTERRUPT(97) \
457 DECLARE_INTERRUPT(96) \
458 DECLARE_INTERRUPT(98) \
459 DECLARE_INTERRUPT(99) \
460 DECLARE_INTERRUPT(100) \
461 DECLARE_INTERRUPT(101) \
462 DECLARE_INTERRUPT(102) \
463 DECLARE_INTERRUPT(103) \
464 DECLARE_INTERRUPT(104) \
465 DECLARE_INTERRUPT(105) \
466 DECLARE_INTERRUPT(106) \
467 DECLARE_INTERRUPT(107) \
468 DECLARE_INTERRUPT(108) \
469 DECLARE_INTERRUPT(109) \
470 DECLARE_INTERRUPT(110) \
471 DECLARE_INTERRUPT(111) \
472 DECLARE_INTERRUPT(112) \
473 DECLARE_INTERRUPT(113) \
474 DECLARE_INTERRUPT(114) \
475 DECLARE_INTERRUPT(115) \
476 DECLARE_INTERRUPT(116) \
477 DECLARE_INTERRUPT(117) \
478 DECLARE_INTERRUPT(118) \
479 DECLARE_INTERRUPT(119) \
480 DECLARE_INTERRUPT(120) \
481 DECLARE_INTERRUPT(121) \
482 DECLARE_INTERRUPT(122) \
483 DECLARE_INTERRUPT(123) \
484 DECLARE_INTERRUPT(124) \
485 DECLARE_INTERRUPT(125) \
486 DECLARE_INTERRUPT(126) \
487 DECLARE_INTERRUPT(127) \
488 DECLARE_INTERRUPT(128) \
489 DECLARE_INTERRUPT(129) \
490 DECLARE_INTERRUPT(130) \
491 DECLARE_INTERRUPT(131) \
492 DECLARE_INTERRUPT(132) \
493 DECLARE_INTERRUPT(133) \
494 DECLARE_INTERRUPT(134) \
495 DECLARE_INTERRUPT(135) \
496 DECLARE_INTERRUPT(136) \
497 DECLARE_INTERRUPT(137) \
498 DECLARE_INTERRUPT(138) \
499 DECLARE_INTERRUPT(139) \
500 DECLARE_INTERRUPT(140) \
501 DECLARE_INTERRUPT(141) \
502 DECLARE_INTERRUPT(142) \
503 DECLARE_INTERRUPT(143) \
504 DECLARE_INTERRUPT(144) \
505 DECLARE_INTERRUPT(145) \
506 DECLARE_INTERRUPT(146) \
507 DECLARE_INTERRUPT(147) \
508 DECLARE_INTERRUPT(148) \
509 DECLARE_INTERRUPT(149) \
510 DECLARE_INTERRUPT(150) \
511 DECLARE_INTERRUPT(151) \
512 DECLARE_INTERRUPT(152) \
513 DECLARE_INTERRUPT(153) \
514 DECLARE_INTERRUPT(154) \
515 DECLARE_INTERRUPT(155) \
516 DECLARE_INTERRUPT(156) \
517 DECLARE_INTERRUPT(157) \
518 DECLARE_INTERRUPT(158) \
519 DECLARE_INTERRUPT(159) \
520 DECLARE_INTERRUPT(160) \
521 DECLARE_INTERRUPT(161) \
522 DECLARE_INTERRUPT(162) \
523 DECLARE_INTERRUPT(163) \
524 DECLARE_INTERRUPT(164) \
525 DECLARE_INTERRUPT(165) \
526 DECLARE_INTERRUPT(166) \
527 DECLARE_INTERRUPT(167) \
528 DECLARE_INTERRUPT(168) \
529 DECLARE_INTERRUPT(169) \
530 DECLARE_INTERRUPT(170) \
531 DECLARE_INTERRUPT(171) \
532 DECLARE_INTERRUPT(172) \
533 DECLARE_INTERRUPT(173) \
534 DECLARE_INTERRUPT(174) \
535 DECLARE_INTERRUPT(175) \
536 DECLARE_INTERRUPT(176) \
537 DECLARE_INTERRUPT(177) \
538 DECLARE_INTERRUPT(178) \
539 DECLARE_INTERRUPT(179) \
540 DECLARE_INTERRUPT(180) \
541 DECLARE_INTERRUPT(181) \
542 DECLARE_INTERRUPT(182) \
543 DECLARE_INTERRUPT(183) \
544 DECLARE_INTERRUPT(184) \
545 DECLARE_INTERRUPT(185) \
546 DECLARE_INTERRUPT(186) \
547 DECLARE_INTERRUPT(187) \
548 DECLARE_INTERRUPT(188) \
549 DECLARE_INTERRUPT(189) \
550 DECLARE_INTERRUPT(190) \
551 DECLARE_INTERRUPT(191) \
552 DECLARE_INTERRUPT(192) \
553 DECLARE_INTERRUPT(193) \
554 DECLARE_INTERRUPT(194) \
555 DECLARE_INTERRUPT(195) \
556 DECLARE_INTERRUPT(196) \
557 DECLARE_INTERRUPT(197) \
558 DECLARE_INTERRUPT(198) \
559 DECLARE_INTERRUPT(199) \
560 DECLARE_INTERRUPT(200) \
561 DECLARE_INTERRUPT(201) \
562 DECLARE_INTERRUPT(202) \
563 DECLARE_INTERRUPT(203) \
564 DECLARE_INTERRUPT(204) \
565 DECLARE_INTERRUPT(205) \
566 DECLARE_INTERRUPT(206) \
567 DECLARE_INTERRUPT(207) \
568 DECLARE_INTERRUPT(208) \
569 DECLARE_INTERRUPT(209) \
570 DECLARE_INTERRUPT(210) \
571 DECLARE_INTERRUPT(211) \
572 DECLARE_INTERRUPT(212) \
573 DECLARE_INTERRUPT(213) \
574 DECLARE_INTERRUPT(214) \
575 DECLARE_INTERRUPT(215) \
576 DECLARE_INTERRUPT(216) \
577 DECLARE_INTERRUPT(217) \
578 DECLARE_INTERRUPT(218) \
579 DECLARE_INTERRUPT(219) \
580 DECLARE_INTERRUPT(220) \
581 DECLARE_INTERRUPT(221) \
582 DECLARE_INTERRUPT(222) \
583 DECLARE_INTERRUPT(223) \
584 DECLARE_INTERRUPT(224) \
585 DECLARE_INTERRUPT(225) \
586 DECLARE_INTERRUPT(226) \
587 DECLARE_INTERRUPT(227) \
588 DECLARE_INTERRUPT(228) \
589 DECLARE_INTERRUPT(229) \
590 DECLARE_INTERRUPT(230) \
591 DECLARE_INTERRUPT(231) \
592 DECLARE_INTERRUPT(232) \
593 DECLARE_INTERRUPT(233) \
594 DECLARE_INTERRUPT(234) \
595 DECLARE_INTERRUPT(235) \
596 DECLARE_INTERRUPT(236) \
597 DECLARE_INTERRUPT(237) \
598 DECLARE_INTERRUPT(238) \
599 DECLARE_INTERRUPT(239) \
600 DECLARE_INTERRUPT(240) \
601 DECLARE_INTERRUPT(241) \
602 DECLARE_INTERRUPT(242) \
603 DECLARE_INTERRUPT(243) \
604 DECLARE_INTERRUPT(244) \
605 DECLARE_INTERRUPT(245) \
606 DECLARE_INTERRUPT(246) \
607 DECLARE_INTERRUPT(247) \
608 DECLARE_INTERRUPT(248) \
609 DECLARE_INTERRUPT(249) \
610 DECLARE_INTERRUPT(250) \
611 DECLARE_INTERRUPT(251) \
612 DECLARE_INTERRUPT(252) \
613 DECLARE_INTERRUPT(253) \
614 DECLARE_INTERRUPT(254) \
615 DECLARE_INTERRUPT(255));
616