akaros/kern/arch/x86/pic.c
<<
>>
Prefs
   1/* Copyright (c) 2009, 2014 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * PIC: 8259 interrupt controller */
   6
   7#include <arch/pic.h>
   8#include <arch/x86.h>
   9#include <atomic.h>
  10#include <assert.h>
  11#include <stdio.h>
  12
  13spinlock_t piclock = SPINLOCK_INITIALIZER_IRQSAVE;
  14
  15/* Remaps the Programmable Interrupt Controller to use IRQs 32-47
  16 * http://wiki.osdev.org/PIC
  17 * Check osdev for a more thorough explanation/implementation.
  18 * http://bochs.sourceforge.net/techspec/PORTS.LST  */
  19void pic_remap(void)
  20{
  21        spin_lock_irqsave(&piclock);
  22        /* start initialization (ICW1) */
  23        outb(PIC1_CMD, 0x11);
  24        outb(PIC2_CMD, 0x11);
  25        /* set new offsets (ICW2) */
  26        outb(PIC1_DATA, PIC1_OFFSET);
  27        outb(PIC2_DATA, PIC2_OFFSET);
  28        /* set up cascading (ICW3) */
  29        outb(PIC1_DATA, 0x04);
  30        outb(PIC2_DATA, 0x02);
  31        /* other stuff (put in 8086/88 mode, or whatever) (ICW4) */
  32        outb(PIC1_DATA, 0x01);
  33        outb(PIC2_DATA, 0x01);
  34        /* Init done, further data R/W access the interrupt mask */
  35        /* set masks, defaulting to all masked for now */
  36        outb(PIC1_DATA, 0xff);
  37        outb(PIC2_DATA, 0xff);
  38        spin_unlock_irqsave(&piclock);
  39}
  40
  41void pic_mask_irq(struct irq_handler *unused, int trap_nr)
  42{
  43        int irq = trap_nr - PIC1_OFFSET;
  44
  45        spin_lock_irqsave(&piclock);
  46        if (irq > 7)
  47                outb(PIC2_DATA, inb(PIC2_DATA) | (1 << (irq - 8)));
  48        else
  49                outb(PIC1_DATA, inb(PIC1_DATA) | (1 << irq));
  50        spin_unlock_irqsave(&piclock);
  51}
  52
  53void pic_unmask_irq(struct irq_handler *unused, int trap_nr)
  54{
  55        int irq = trap_nr - PIC1_OFFSET;
  56        printd("PIC unmask for TRAP %d, IRQ %d\n", trap_nr, irq);
  57        spin_lock_irqsave(&piclock);
  58        if (irq > 7) {
  59                outb(PIC2_DATA, inb(PIC2_DATA) & ~(1 << (irq - 8)));
  60                // make sure irq2 is unmasked
  61                outb(PIC1_DATA, inb(PIC1_DATA) & 0xfb);
  62        } else
  63                outb(PIC1_DATA, inb(PIC1_DATA) & ~(1 << irq));
  64        spin_unlock_irqsave(&piclock);
  65}
  66
  67void pic_mask_all(void)
  68{
  69        for (int i = 0 + PIC1_OFFSET; i < 16 + PIC1_OFFSET; i++)
  70                pic_mask_irq(0, i);
  71}
  72
  73/* Aka, the IMR.  Simply reading the data port are OCW1s. */
  74uint16_t pic_get_mask(void)
  75{
  76        uint16_t ret;
  77
  78        spin_lock_irqsave(&piclock);
  79        ret = (inb(PIC2_DATA) << 8) | inb(PIC1_DATA);
  80        spin_unlock_irqsave(&piclock);
  81        return ret;
  82}
  83
  84static uint16_t __pic_get_irq_reg(int ocw3)
  85{
  86        uint16_t ret;
  87
  88        spin_lock_irqsave(&piclock);
  89        /* OCW3 to PIC CMD to get the register values.  PIC2 is chained, and
  90         * represents IRQs 8-15.  PIC1 is IRQs 0-7, with 2 being the chain */
  91        outb(PIC1_CMD, ocw3);
  92        outb(PIC2_CMD, ocw3);
  93        ret = (inb(PIC2_CMD) << 8) | inb(PIC1_CMD);
  94        spin_unlock_irqsave(&piclock);
  95        return ret;
  96}
  97
  98/* Returns the combined value of the cascaded PICs irq request register */
  99uint16_t pic_get_irr(void)
 100{
 101        return __pic_get_irq_reg(PIC_READ_IRR);
 102}
 103
 104/* Returns the combined value of the cascaded PICs irq service register */
 105uint16_t pic_get_isr(void)
 106{
 107        return __pic_get_irq_reg(PIC_READ_ISR);
 108}
 109
 110/* Takes a raw vector/trap number (32-47), not a device IRQ (0-15) */
 111bool pic_check_spurious(int trap_nr)
 112{
 113        /* the PIC may send spurious irqs via one of the chips irq 7.  if the
 114         * isr doesn't show that irq, then it was spurious, and we don't send an
 115         * eoi.  Check out http://wiki.osdev.org/8259_PIC#Spurious_IRQs */
 116        if ((trap_nr == PIC1_SPURIOUS) && !(pic_get_isr() & (1 << 7))) {
 117                /* want to know if this happens */
 118                printd("Spurious PIC1 irq!\n");
 119                return TRUE;
 120        }
 121        if ((trap_nr == PIC2_SPURIOUS) && !(pic_get_isr() & (1 << 15))) {
 122                /* want to know if this happens */
 123                printd("Spurious PIC2 irq!\n");
 124                /* for the cascaded PIC, we *do* need to send an EOI to the
 125                 * master's cascade irq (2). */
 126                pic_send_eoi(2 + PIC1_OFFSET);
 127                return TRUE;
 128        }
 129        return FALSE;
 130}
 131
 132void pic_send_eoi(int trap_nr)
 133{
 134        int irq = trap_nr - PIC1_OFFSET;
 135
 136        spin_lock_irqsave(&piclock);
 137        // all irqs beyond the first seven need to be chained to the slave
 138        if (irq > 7)
 139                outb(PIC2_CMD, PIC_EOI);
 140        outb(PIC1_CMD, PIC_EOI);
 141        spin_unlock_irqsave(&piclock);
 142}
 143