interrupts.c 12 KB

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