interrupts.c 14 KB

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