diff options
Diffstat (limited to 'src/i8259.c')
-rw-r--r-- | src/i8259.c | 257 |
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); -} |