interrupts.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /*
  2. * (C) Copyright 2002
  3. * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <malloc.h>
  25. #include <asm/io.h>
  26. #include <asm/i8259.h>
  27. #include <asm/ibmpc.h>
  28. struct idt_entry {
  29. u16 base_low;
  30. u16 selector;
  31. u8 res;
  32. u8 access;
  33. u16 base_high;
  34. } __attribute__ ((packed));
  35. struct idt_entry idt[256];
  36. #define MAX_IRQ 16
  37. typedef struct irq_handler {
  38. struct irq_handler *next;
  39. interrupt_handler_t* isr_func;
  40. void *isr_data;
  41. } irq_handler_t;
  42. #define IRQ_DISABLED 1
  43. typedef struct {
  44. irq_handler_t *handler;
  45. unsigned long status;
  46. } irq_desc_t;
  47. static irq_desc_t irq_table[MAX_IRQ];
  48. asm ("irq_return:\n"
  49. " addl $4, %esp\n"
  50. " popa\n"
  51. " iret\n");
  52. asm ("exp_return:\n"
  53. " addl $12, %esp\n"
  54. " pop %esp\n"
  55. " popa\n"
  56. " iret\n");
  57. char exception_stack[4096];
  58. #define DECLARE_INTERRUPT(x) \
  59. asm(".globl irq_"#x"\n" \
  60. "irq_"#x":\n" \
  61. "pusha \n" \
  62. "pushl $"#x"\n" \
  63. "pushl $irq_return\n" \
  64. "jmp do_irq\n"); \
  65. void __attribute__ ((regparm(0))) irq_##x(void)
  66. #define DECLARE_EXCEPTION(x, f) \
  67. asm(".globl exp_"#x"\n" \
  68. "exp_"#x":\n" \
  69. "pusha \n" \
  70. "movl %esp, %ebx\n" \
  71. "movl $exception_stack, %eax\n" \
  72. "movl %eax, %esp \n" \
  73. "pushl %ebx\n" \
  74. "movl 32(%esp), %ebx\n" \
  75. "xorl %edx, %edx\n" \
  76. "movw 36(%esp), %dx\n" \
  77. "pushl %edx\n" \
  78. "pushl %ebx\n" \
  79. "pushl $"#x"\n" \
  80. "pushl $exp_return\n" \
  81. "jmp "#f"\n"); \
  82. void __attribute__ ((regparm(0))) exp_##x(void)
  83. DECLARE_EXCEPTION(0, divide_exception_entry); /* Divide exception */
  84. DECLARE_EXCEPTION(1, debug_exception_entry); /* Debug exception */
  85. DECLARE_EXCEPTION(2, nmi_entry); /* NMI */
  86. DECLARE_EXCEPTION(3, unknown_exception_entry); /* Breakpoint/Coprocessor Error */
  87. DECLARE_EXCEPTION(4, unknown_exception_entry); /* Overflow */
  88. DECLARE_EXCEPTION(5, unknown_exception_entry); /* Bounds */
  89. DECLARE_EXCEPTION(6, invalid_instruction_entry); /* Invalid instruction */
  90. DECLARE_EXCEPTION(7, unknown_exception_entry); /* Device not present */
  91. DECLARE_EXCEPTION(8, double_fault_entry); /* Double fault */
  92. DECLARE_EXCEPTION(9, unknown_exception_entry); /* Co-processor segment overrun */
  93. DECLARE_EXCEPTION(10, invalid_tss_exception_entry);/* Invalid TSS */
  94. DECLARE_EXCEPTION(11, seg_fault_entry); /* Segment not present */
  95. DECLARE_EXCEPTION(12, stack_fault_entry); /* Stack overflow */
  96. DECLARE_EXCEPTION(13, gpf_entry); /* GPF */
  97. DECLARE_EXCEPTION(14, page_fault_entry); /* PF */
  98. DECLARE_EXCEPTION(15, unknown_exception_entry); /* Reserved */
  99. DECLARE_EXCEPTION(16, fp_exception_entry); /* Floating point */
  100. DECLARE_EXCEPTION(17, alignment_check_entry); /* alignment check */
  101. DECLARE_EXCEPTION(18, machine_check_entry); /* machine check */
  102. DECLARE_EXCEPTION(19, unknown_exception_entry); /* Reserved */
  103. DECLARE_EXCEPTION(20, unknown_exception_entry); /* Reserved */
  104. DECLARE_EXCEPTION(21, unknown_exception_entry); /* Reserved */
  105. DECLARE_EXCEPTION(22, unknown_exception_entry); /* Reserved */
  106. DECLARE_EXCEPTION(23, unknown_exception_entry); /* Reserved */
  107. DECLARE_EXCEPTION(24, unknown_exception_entry); /* Reserved */
  108. DECLARE_EXCEPTION(25, unknown_exception_entry); /* Reserved */
  109. DECLARE_EXCEPTION(26, unknown_exception_entry); /* Reserved */
  110. DECLARE_EXCEPTION(27, unknown_exception_entry); /* Reserved */
  111. DECLARE_EXCEPTION(28, unknown_exception_entry); /* Reserved */
  112. DECLARE_EXCEPTION(29, unknown_exception_entry); /* Reserved */
  113. DECLARE_EXCEPTION(30, unknown_exception_entry); /* Reserved */
  114. DECLARE_EXCEPTION(31, unknown_exception_entry); /* Reserved */
  115. DECLARE_INTERRUPT(0);
  116. DECLARE_INTERRUPT(1);
  117. DECLARE_INTERRUPT(3);
  118. DECLARE_INTERRUPT(4);
  119. DECLARE_INTERRUPT(5);
  120. DECLARE_INTERRUPT(6);
  121. DECLARE_INTERRUPT(7);
  122. DECLARE_INTERRUPT(8);
  123. DECLARE_INTERRUPT(9);
  124. DECLARE_INTERRUPT(10);
  125. DECLARE_INTERRUPT(11);
  126. DECLARE_INTERRUPT(12);
  127. DECLARE_INTERRUPT(13);
  128. DECLARE_INTERRUPT(14);
  129. DECLARE_INTERRUPT(15);
  130. void __attribute__ ((regparm(0))) default_isr(void);
  131. asm ("default_isr: iret\n");
  132. void disable_irq(int irq)
  133. {
  134. if (irq >= MAX_IRQ) {
  135. return;
  136. }
  137. irq_table[irq].status |= IRQ_DISABLED;
  138. }
  139. void enable_irq(int irq)
  140. {
  141. if (irq >= MAX_IRQ) {
  142. return;
  143. }
  144. irq_table[irq].status &= ~IRQ_DISABLED;
  145. }
  146. /* masks one specific IRQ in the PIC */
  147. static void unmask_irq(int irq)
  148. {
  149. int imr_port;
  150. if (irq >= MAX_IRQ) {
  151. return;
  152. }
  153. if (irq > 7) {
  154. imr_port = SLAVE_PIC + IMR;
  155. } else {
  156. imr_port = MASTER_PIC + IMR;
  157. }
  158. outb(inb(imr_port)&~(1<<(irq&7)), imr_port);
  159. }
  160. /* unmasks one specific IRQ in the PIC */
  161. static void mask_irq(int irq)
  162. {
  163. int imr_port;
  164. if (irq >= MAX_IRQ) {
  165. return;
  166. }
  167. if (irq > 7) {
  168. imr_port = SLAVE_PIC + IMR;
  169. } else {
  170. imr_port = MASTER_PIC + IMR;
  171. }
  172. outb(inb(imr_port)|(1<<(irq&7)), imr_port);
  173. }
  174. /* issue a Specific End Of Interrupt instruciton */
  175. static void specific_eoi(int irq)
  176. {
  177. /* If it is on the slave PIC this have to be performed on
  178. * both the master and the slave PICs */
  179. if (irq > 7) {
  180. outb(OCW2_SEOI|(irq&7), SLAVE_PIC + OCW2);
  181. irq = SEOI_IR2; /* also do IR2 on master */
  182. }
  183. outb(OCW2_SEOI|irq, MASTER_PIC + OCW2);
  184. }
  185. void __attribute__ ((regparm(0))) do_irq(int irq)
  186. {
  187. mask_irq(irq);
  188. if (irq_table[irq].status & IRQ_DISABLED) {
  189. unmask_irq(irq);
  190. specific_eoi(irq);
  191. return;
  192. }
  193. if (NULL != irq_table[irq].handler) {
  194. irq_handler_t *handler;
  195. for (handler = irq_table[irq].handler;
  196. NULL!= handler; handler = handler->next) {
  197. handler->isr_func(handler->isr_data);
  198. }
  199. } else {
  200. if ((irq & 7) != 7) {
  201. printf("Spurious irq %d\n", irq);
  202. }
  203. }
  204. unmask_irq(irq);
  205. specific_eoi(irq);
  206. }
  207. void __attribute__ ((regparm(0))) unknown_exception_entry(int cause, int ip, int seg)
  208. {
  209. printf("Unknown Exception %d at %04x:%08x\n", cause, seg, ip);
  210. }
  211. void __attribute__ ((regparm(0))) divide_exception_entry(int cause, int ip, int seg)
  212. {
  213. printf("Divide Error (Division by zero) at %04x:%08x\n", seg, ip);
  214. while(1);
  215. }
  216. void __attribute__ ((regparm(0))) debug_exception_entry(int cause, int ip, int seg)
  217. {
  218. printf("Debug Interrupt (Single step) at %04x:%08x\n", seg, ip);
  219. }
  220. void __attribute__ ((regparm(0))) nmi_entry(int cause, int ip, int seg)
  221. {
  222. printf("NMI Interrupt at %04x:%08x\n", seg, ip);
  223. }
  224. void __attribute__ ((regparm(0))) invalid_instruction_entry(int cause, int ip, int seg)
  225. {
  226. printf("Invalid Instruction at %04x:%08x\n", seg, ip);
  227. while(1);
  228. }
  229. void __attribute__ ((regparm(0))) double_fault_entry(int cause, int ip, int seg)
  230. {
  231. printf("Double fault at %04x:%08x\n", seg, ip);
  232. while(1);
  233. }
  234. void __attribute__ ((regparm(0))) invalid_tss_exception_entry(int cause, int ip, int seg)
  235. {
  236. printf("Invalid TSS at %04x:%08x\n", seg, ip);
  237. }
  238. void __attribute__ ((regparm(0))) seg_fault_entry(int cause, int ip, int seg)
  239. {
  240. printf("Segmentation fault at %04x:%08x\n", seg, ip);
  241. while(1);
  242. }
  243. void __attribute__ ((regparm(0))) stack_fault_entry(int cause, int ip, int seg)
  244. {
  245. printf("Stack fault at %04x:%08x\n", seg, ip);
  246. while(1);
  247. }
  248. void __attribute__ ((regparm(0))) gpf_entry(int cause, int ip, int seg)
  249. {
  250. printf("General protection fault at %04x:%08x\n", seg, ip);
  251. }
  252. void __attribute__ ((regparm(0))) page_fault_entry(int cause, int ip, int seg)
  253. {
  254. printf("Page fault at %04x:%08x\n", seg, ip);
  255. while(1);
  256. }
  257. void __attribute__ ((regparm(0))) fp_exception_entry(int cause, int ip, int seg)
  258. {
  259. printf("Floating point exception at %04x:%08x\n", seg, ip);
  260. }
  261. void __attribute__ ((regparm(0))) alignment_check_entry(int cause, int ip, int seg)
  262. {
  263. printf("Alignment check at %04x:%08x\n", seg, ip);
  264. }
  265. void __attribute__ ((regparm(0))) machine_check_entry(int cause, int ip, int seg)
  266. {
  267. printf("Machine check exception at %04x:%08x\n", seg, ip);
  268. }
  269. void irq_install_handler(int ino, interrupt_handler_t *func, void *pdata)
  270. {
  271. int status;
  272. if (ino>MAX_IRQ) {
  273. return;
  274. }
  275. if (NULL != irq_table[ino].handler) {
  276. return;
  277. }
  278. status = disable_interrupts();
  279. irq_table[ino].handler = malloc(sizeof(irq_handler_t));
  280. if (NULL == irq_table[ino].handler) {
  281. return;
  282. }
  283. memset(irq_table[ino].handler, 0, sizeof(irq_handler_t));
  284. irq_table[ino].handler->isr_func = func;
  285. irq_table[ino].handler->isr_data = pdata;
  286. if (status) {
  287. enable_interrupts();
  288. }
  289. unmask_irq(ino);
  290. return;
  291. }
  292. void irq_free_handler(int ino)
  293. {
  294. int status;
  295. if (ino>MAX_IRQ) {
  296. return;
  297. }
  298. status = disable_interrupts();
  299. mask_irq(ino);
  300. if (NULL == irq_table[ino].handler) {
  301. return;
  302. }
  303. free(irq_table[ino].handler);
  304. irq_table[ino].handler=NULL;
  305. if (status) {
  306. enable_interrupts();
  307. }
  308. return;
  309. }
  310. asm ("idt_ptr:\n"
  311. ".word 0x800\n" /* size of the table 8*256 bytes */
  312. ".long idt\n" /* offset */
  313. ".word 0x18\n");/* data segment */
  314. static void set_vector(int intnum, void *routine)
  315. {
  316. idt[intnum].base_high = (u16)((u32)(routine)>>16);
  317. idt[intnum].base_low = (u16)((u32)(routine)&0xffff);
  318. }
  319. int interrupt_init(void)
  320. {
  321. int i;
  322. /* Just in case... */
  323. disable_interrupts();
  324. /* Initialize the IDT and stuff */
  325. memset(irq_table, 0, sizeof(irq_table));
  326. /* Setup the IDT */
  327. for (i=0;i<256;i++) {
  328. idt[i].access = 0x8e;
  329. idt[i].res = 0;
  330. idt[i].selector = 0x10;
  331. set_vector(i, default_isr);
  332. }
  333. asm ("cs lidt idt_ptr\n");
  334. /* Setup exceptions */
  335. set_vector(0x00, exp_0);
  336. set_vector(0x01, exp_1);
  337. set_vector(0x02, exp_2);
  338. set_vector(0x03, exp_3);
  339. set_vector(0x04, exp_4);
  340. set_vector(0x05, exp_5);
  341. set_vector(0x06, exp_6);
  342. set_vector(0x07, exp_7);
  343. set_vector(0x08, exp_8);
  344. set_vector(0x09, exp_9);
  345. set_vector(0x0a, exp_10);
  346. set_vector(0x0b, exp_11);
  347. set_vector(0x0c, exp_12);
  348. set_vector(0x0d, exp_13);
  349. set_vector(0x0e, exp_14);
  350. set_vector(0x0f, exp_15);
  351. set_vector(0x10, exp_16);
  352. set_vector(0x11, exp_17);
  353. set_vector(0x12, exp_18);
  354. set_vector(0x13, exp_19);
  355. set_vector(0x14, exp_20);
  356. set_vector(0x15, exp_21);
  357. set_vector(0x16, exp_22);
  358. set_vector(0x17, exp_23);
  359. set_vector(0x18, exp_24);
  360. set_vector(0x19, exp_25);
  361. set_vector(0x1a, exp_26);
  362. set_vector(0x1b, exp_27);
  363. set_vector(0x1c, exp_28);
  364. set_vector(0x1d, exp_29);
  365. set_vector(0x1e, exp_30);
  366. set_vector(0x1f, exp_31);
  367. /* Setup interrupts */
  368. set_vector(0x20, irq_0);
  369. set_vector(0x21, irq_1);
  370. set_vector(0x23, irq_3);
  371. set_vector(0x24, irq_4);
  372. set_vector(0x25, irq_5);
  373. set_vector(0x26, irq_6);
  374. set_vector(0x27, irq_7);
  375. set_vector(0x28, irq_8);
  376. set_vector(0x29, irq_9);
  377. set_vector(0x2a, irq_10);
  378. set_vector(0x2b, irq_11);
  379. set_vector(0x2c, irq_12);
  380. set_vector(0x2d, irq_13);
  381. set_vector(0x2e, irq_14);
  382. set_vector(0x2f, irq_15);
  383. /* vectors 0x30-0x3f are reserved for irq 16-31 */
  384. /* Mask all interrupts */
  385. outb(0xff, MASTER_PIC + IMR);
  386. outb(0xff, SLAVE_PIC + IMR);
  387. /* Master PIC */
  388. outb(ICW1_SEL|ICW1_EICW4, MASTER_PIC + ICW1);
  389. outb(0x20, MASTER_PIC + ICW2); /* Place master PIC interrupts at INT20 */
  390. outb(IR2, MASTER_PIC + ICW3); /* ICW3, One slevc PIC is present */
  391. outb(ICW4_PM, MASTER_PIC + ICW4);
  392. for (i=0;i<8;i++) {
  393. outb(OCW2_SEOI|i, MASTER_PIC + OCW2);
  394. }
  395. /* Slave PIC */
  396. outb(ICW1_SEL|ICW1_EICW4, SLAVE_PIC + ICW1);
  397. outb(0x28, SLAVE_PIC + ICW2); /* Place slave PIC interrupts at INT28 */
  398. outb(0x02, SLAVE_PIC + ICW3); /* Slave ID */
  399. outb(ICW4_PM, SLAVE_PIC + ICW4);
  400. for (i=0;i<8;i++) {
  401. outb(OCW2_SEOI|i, SLAVE_PIC + OCW2);
  402. }
  403. /* enable cascade interrerupt */
  404. outb(0xfb, MASTER_PIC + IMR);
  405. outb(0xff, SLAVE_PIC + IMR);
  406. /* It is now safe to enable interrupts */
  407. enable_interrupts();
  408. return 0;
  409. }
  410. void enable_interrupts(void)
  411. {
  412. asm("sti\n");
  413. }
  414. int disable_interrupts(void)
  415. {
  416. long flags;
  417. asm volatile ("pushfl ; popl %0 ; cli\n" : "=g" (flags) : );
  418. return (flags&0x200); /* IE flags is bit 9 */
  419. }
  420. #ifdef CFG_RESET_GENERIC
  421. void __attribute__ ((regparm(0))) generate_gpf(void);
  422. asm(".globl generate_gpf\n"
  423. "generate_gpf:\n"
  424. "ljmp $0x70, $0x47114711\n"); /* segment 0x70 is an arbitrary segment which does not
  425. * exist */
  426. void reset_cpu(ulong addr)
  427. {
  428. set_vector(13, generate_gpf); /* general protection fault handler */
  429. set_vector(8, generate_gpf); /* double fault handler */
  430. generate_gpf(); /* start the show */
  431. }
  432. #endif