summaryrefslogtreecommitdiff
path: root/src/i8259.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i8259.c')
-rw-r--r--src/i8259.c257
1 files changed, 0 insertions, 257 deletions
diff --git a/src/i8259.c b/src/i8259.c
deleted file mode 100644
index aed7068..0000000
--- a/src/i8259.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2017 Richard Braun.
- * Copyright (c) 2017 Jerko Lenstra.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- *
- * IRQ means Interrupt ReQuest. They're used by external hardware to signal
- * the CPU, and in turn the OS, that an external event has happened and
- * requires processing. The usual model is shown in the image at
- * https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/PIC_Hardware_interrupt_path.svg/300px-PIC_Hardware_interrupt_path.svg.png.
- *
- * This driver implements IRQ handling on the Intel 8259 PIC. The IBM PC/AT
- * actually uses 2 of these PICs for external interrupt handling, as shown
- * in https://masherz.files.wordpress.com/2010/08/217.jpg. The public
- * interface completely hides this detail and considers all given IRQs
- * as logical indexes, used to find the corresponding PIC (master or slave)
- * and the local IRQ on that PIC.
- *
- * 8259 datasheet :
- * https://pdos.csail.mit.edu/6.828/2010/readings/hardware/8259A.pdf
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <lib/macros.h>
-
-#include "cpu.h"
-#include "i8259.h"
-#include "io.h"
-
-#define I8259_IRQ_CASCADE 2 /* IRQ used for cascading on the master */
-#define I8259_NR_IRQS 8
-
-/*
- * Initialization Control Word 1 bits.
- */
-#define I8259_ICW1_ICW4 0x01 /* State that a 4th ICW will be sent */
-#define I8259_ICW1_INIT 0x10 /* This bit must be set */
-
-/*
- * Initialization Control Word 4 bits.
- */
-#define I8259_ICW4_8086 0x01 /* 8086 mode, as x86 is still compatible
- with the old 8086 processor */
-
-#define I8259_OCW2_EOI 0x20 /* End of interrupt control word */
-
-enum {
- I8259_PIC_ID_MASTER,
- I8259_PIC_ID_SLAVE,
- I8259_NR_PICS
-};
-
-/*
- * Intel 8259 programmable interrupt controller.
- */
-struct i8259_pic {
- uint16_t cmd_port; /* Command I/O port of the PIC */
- uint16_t data_port; /* Data I/O port of the PIC */
- uint8_t imr; /* Cached value of the IMR register */
- bool master; /* True if this PIC is the master */
-};
-
-/*
- * Static instances of PIC objects.
- */
-static struct i8259_pic i8259_pics[] = {
- [I8259_PIC_ID_MASTER] = {
- .cmd_port = 0x20,
- .data_port = 0x21,
- .imr = 0xff,
- .master = true,
- },
- [I8259_PIC_ID_SLAVE] = {
- .cmd_port = 0xa0,
- .data_port = 0xa1,
- .imr = 0xff,
- .master = false,
- },
-};
-
-static struct i8259_pic *
-i8259_get_pic(unsigned int id)
-{
- assert(id < ARRAY_SIZE(i8259_pics));
- return &i8259_pics[id];
-}
-
-static int
-i8259_convert_global_irq(unsigned int irq, struct i8259_pic **pic,
- unsigned int *local_irq)
-{
- int error;
-
- if (irq < I8259_NR_IRQS) {
- *pic = i8259_get_pic(I8259_PIC_ID_MASTER);
-
- if (local_irq) {
- *local_irq = irq;
- }
-
- error = 0;
- } else if (irq < (I8259_NR_IRQS * I8259_NR_PICS)) {
- *pic = i8259_get_pic(I8259_PIC_ID_SLAVE);
-
- if (local_irq) {
- *local_irq = irq - I8259_NR_IRQS;
- }
-
- error = 0;
- } else {
- *local_irq = 0;
- error = EINVAL;
- }
-
- return error;
-}
-
-static void
-i8259_pic_write_cmd(const struct i8259_pic *pic, uint8_t byte)
-{
- io_write(pic->cmd_port, byte);
-}
-
-static void
-i8259_pic_write_data(const struct i8259_pic *pic, uint8_t byte)
-{
- io_write(pic->data_port, byte);
-}
-
-static void
-i8259_pic_apply_imr(const struct i8259_pic *pic)
-{
- io_write(pic->data_port, pic->imr);
-}
-
-static void
-i8259_pic_enable_irq(struct i8259_pic *pic, unsigned int irq)
-{
- assert(irq < I8259_NR_IRQS);
-
- pic->imr &= ~(1 << irq);
- i8259_pic_apply_imr(pic);
-}
-
-static void
-i8259_pic_disable_irq(struct i8259_pic *pic, unsigned int irq)
-{
- assert(irq < I8259_NR_IRQS);
-
- pic->imr |= (1 << irq);
- i8259_pic_apply_imr(pic);
-}
-
-static void
-i8259_pic_eoi(struct i8259_pic *pic)
-{
- io_write(pic->cmd_port, I8259_OCW2_EOI);
-}
-
-void
-i8259_setup(void)
-{
- struct i8259_pic *master, *slave;
-
- master = i8259_get_pic(I8259_PIC_ID_MASTER);
- slave = i8259_get_pic(I8259_PIC_ID_SLAVE);
-
- i8259_pic_write_cmd(master, I8259_ICW1_INIT | I8259_ICW1_ICW4);
- i8259_pic_write_cmd(slave, I8259_ICW1_INIT | I8259_ICW1_ICW4);
- i8259_pic_write_data(master, CPU_IDT_VECT_IRQ_BASE);
- i8259_pic_write_data(slave, CPU_IDT_VECT_IRQ_BASE + I8259_NR_IRQS);
- i8259_pic_write_data(master, 1 << I8259_IRQ_CASCADE);
- i8259_pic_write_data(slave, I8259_IRQ_CASCADE);
- i8259_pic_write_data(master, I8259_ICW4_8086);
- i8259_pic_write_data(slave, I8259_ICW4_8086);
-
- i8259_pic_enable_irq(master, I8259_IRQ_CASCADE);
- i8259_pic_apply_imr(master);
- i8259_pic_apply_imr(slave);
-}
-
-void
-i8259_irq_enable(unsigned int irq)
-{
- struct i8259_pic *pic;
- unsigned int local_irq;
- int error;
-
- error = i8259_convert_global_irq(irq, &pic, &local_irq);
- assert(!error);
- i8259_pic_enable_irq(pic, local_irq);
-}
-
-void
-i8259_irq_disable(unsigned int irq)
-{
- struct i8259_pic *pic;
- unsigned int local_irq;
- int error;
-
- error = i8259_convert_global_irq(irq, &pic, &local_irq);
- assert(!error);
- i8259_pic_disable_irq(pic, local_irq);
-}
-
-void
-i8259_irq_eoi(unsigned int irq)
-{
- struct i8259_pic *pic;
- int error;
-
- assert(!cpu_intr_enabled());
-
- error = i8259_convert_global_irq(irq, &pic, NULL);
- assert(!error);
-
- if (!pic->master) {
- /*
- * The order in which EOI messages are sent (master then slave or the
- * reverse) is irrelevant :
- * - If the slave is sent the EOI message first, it may raise another
- * interrupt right away, in which case it will be pending at the
- * master until the latter is sent the EOI message too.
- * - If the master is sent the EOI message first, it may raise another
- * interrupt right away, in which case it will be pending at the
- * processor until interrupts are reenabled, assuming that this
- * function is called with interrupts disabled, and that interrupts
- * remain disabled until control is returned to the interrupted
- * thread.
- */
- i8259_pic_eoi(i8259_get_pic(I8259_PIC_ID_MASTER));
- }
-
- i8259_pic_eoi(pic);
-}