summaryrefslogtreecommitdiff
path: root/arch/x86/machine/pic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/machine/pic.c')
-rw-r--r--arch/x86/machine/pic.c146
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)
{