interrupts.c 14 KB

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