diff options
Diffstat (limited to 'arch/x86/machine/pic.c')
-rw-r--r-- | arch/x86/machine/pic.c | 146 |
1 files changed, 128 insertions, 18 deletions
diff --git a/arch/x86/machine/pic.c b/arch/x86/machine/pic.c index 412135c..fed8c97 100644 --- a/arch/x86/machine/pic.c +++ b/arch/x86/machine/pic.c @@ -19,9 +19,11 @@ #include <kern/assert.h> #include <kern/init.h> +#include <kern/intr.h> #include <kern/panic.h> -#include <machine/io.h> #include <machine/cpu.h> +#include <machine/io.h> +#include <machine/lapic.h> #include <machine/pic.h> #include <machine/trap.h> @@ -48,29 +50,43 @@ #define PIC_SLAVE_INTR 2 #define PIC_SPURIOUS_INTR 7 #define PIC_NR_INTRS 8 +#define PIC_MAX_INTR ((PIC_NR_INTRS * 2) - 1) -void __init -pic_setup(void) +static unsigned int pic_nr_slave_intrs; + +static uint8_t pic_master_mask; +static uint8_t pic_slave_mask; + +static bool +pic_is_slave_intr(unsigned int intr) { - /* ICW 1 - State that ICW 4 will be sent */ - io_write_byte(PIC_MASTER_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4); - io_write_byte(PIC_SLAVE_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4); + assert(intr <= PIC_MAX_INTR); + return (intr >= PIC_NR_INTRS); +} - /* ICW 2 */ - io_write_byte(PIC_MASTER_IMR, TRAP_INTR_FIRST); - io_write_byte(PIC_SLAVE_IMR, TRAP_INTR_FIRST + PIC_NR_INTRS); +static void +pic_inc_slave_intrs(void) +{ + if (pic_nr_slave_intrs == 0) { + pic_master_mask |= 1 << PIC_SLAVE_INTR; + io_write_byte(PIC_MASTER_IMR, pic_master_mask); + } - /* ICW 3 - Set up cascading */ - io_write_byte(PIC_MASTER_IMR, 1 << PIC_SLAVE_INTR); - io_write_byte(PIC_SLAVE_IMR, PIC_SLAVE_INTR); + pic_nr_slave_intrs++; + assert(pic_nr_slave_intrs != 0); +} - /* ICW 4 - Set 8086 mode */ - io_write_byte(PIC_MASTER_IMR, PIC_ICW4_8086); - io_write_byte(PIC_SLAVE_IMR, PIC_ICW4_8086); +static void +pic_dec_slave_intrs(void) +{ + assert(pic_nr_slave_intrs != 0); - /* OCW 1 - Mask all interrupts */ - io_write_byte(PIC_MASTER_IMR, 0xff); - io_write_byte(PIC_SLAVE_IMR, 0xff); + pic_nr_slave_intrs--; + + if (pic_nr_slave_intrs == 0) { + pic_master_mask &= ~(1 << PIC_SLAVE_INTR); + io_write_byte(PIC_MASTER_IMR, pic_master_mask); + } } static void @@ -90,6 +106,100 @@ pic_read_isr(uint16_t port) return io_read_byte(port); } +static void +pic_ops_enable(void *priv, unsigned int intr, unsigned int cpu) +{ + (void)priv; + (void)cpu; + + if (pic_is_slave_intr(intr)) { + pic_slave_mask &= ~(1 << (intr - PIC_NR_INTRS)); + io_write_byte(PIC_SLAVE_IMR, pic_slave_mask); + pic_inc_slave_intrs(); + } else { + pic_master_mask &= ~(1 << intr); + io_write_byte(PIC_MASTER_IMR, pic_master_mask); + } +} + +static void +pic_ops_disable(void *priv, unsigned int intr) +{ + (void)priv; + + if (pic_is_slave_intr(intr)) { + pic_dec_slave_intrs(); + pic_slave_mask |= 1 << (intr - PIC_NR_INTRS); + io_write_byte(PIC_SLAVE_IMR, pic_slave_mask); + } else { + pic_master_mask |= 1 << intr; + io_write_byte(PIC_MASTER_IMR, pic_master_mask); + } +} + +static void +pic_ops_eoi(void *priv, unsigned int intr) +{ + (void)priv; + pic_eoi(intr); +} + +static const struct intr_ops pic_ops = { + .enable = pic_ops_enable, + .disable = pic_ops_disable, + .eoi = pic_ops_eoi, +}; + +static void +pic_intr(struct trap_frame *frame) +{ + intr_handle(frame->vector - TRAP_INTR_FIRST); +} + +static void __init +pic_register(void) +{ + unsigned int intr; + + intr_register_ctl(&pic_ops, NULL, 0, PIC_MAX_INTR); + + for (intr = 0; intr <= PIC_MAX_INTR; intr++) { + trap_register(TRAP_INTR_FIRST + intr, pic_intr); + } +} + +void __init +pic_setup(void) +{ + pic_nr_slave_intrs = 0; + pic_master_mask = 0xff; + pic_slave_mask = 0xff; + + /* ICW 1 - State that ICW 4 will be sent */ + io_write_byte(PIC_MASTER_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4); + io_write_byte(PIC_SLAVE_CMD, PIC_ICW1_INIT | PIC_ICW1_IC4); + + /* ICW 2 */ + io_write_byte(PIC_MASTER_IMR, TRAP_INTR_FIRST); + io_write_byte(PIC_SLAVE_IMR, TRAP_INTR_FIRST + PIC_NR_INTRS); + + /* ICW 3 - Set up cascading */ + io_write_byte(PIC_MASTER_IMR, 1 << PIC_SLAVE_INTR); + io_write_byte(PIC_SLAVE_IMR, PIC_SLAVE_INTR); + + /* ICW 4 - Set 8086 mode */ + io_write_byte(PIC_MASTER_IMR, PIC_ICW4_8086); + io_write_byte(PIC_SLAVE_IMR, PIC_ICW4_8086); + + /* OCW 1 - Mask all interrupts */ + io_write_byte(PIC_MASTER_IMR, pic_master_mask); + io_write_byte(PIC_SLAVE_IMR, pic_slave_mask); + + if (lapic_unused()) { + pic_register(); + } +} + void pic_spurious_intr(struct trap_frame *frame) { |