x86: add irq support
parent
89f3393b8b
commit
4679b7cee5
@ -0,0 +1,59 @@
|
||||
/* See the end of this file for copyright and license terms. */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @brief Arch specific maximum number of IRQs (x86 8259 PIC version) */
|
||||
#define NUM_IRQ 16
|
||||
|
||||
#include <gay/cdefs.h>
|
||||
|
||||
/** @brief Low level interrupt controller init routine (x86 version). */
|
||||
void arch_irq_init(void);
|
||||
|
||||
/**
|
||||
* @brief Low level IRQ unmasking routine (x86 version).
|
||||
* All of the sanity checks have already been done in `irq_enable()`, so this
|
||||
* method expects the IRQ number to be valid and have an associated handler.
|
||||
*
|
||||
* @param number IRQ number
|
||||
*/
|
||||
void arch_irq_enable(unsigned int number);
|
||||
|
||||
/**
|
||||
* @brief Low level IRQ masking routine (x86 version).
|
||||
* Like with `arch_irq_enable()`, this method does not do error checking.
|
||||
*
|
||||
* @param number IRQ number
|
||||
*/
|
||||
void arch_irq_disable(unsigned int number);
|
||||
|
||||
/* generated in irq.S */
|
||||
extern void _x86_isr_irq0(void);
|
||||
extern void _x86_isr_irq1(void);
|
||||
extern void _x86_isr_irq3(void);
|
||||
extern void _x86_isr_irq4(void);
|
||||
extern void _x86_isr_irq5(void);
|
||||
extern void _x86_isr_irq6(void);
|
||||
extern void _x86_isr_irq7(void);
|
||||
extern void _x86_isr_irq8(void);
|
||||
extern void _x86_isr_irq9(void);
|
||||
extern void _x86_isr_irq10(void);
|
||||
extern void _x86_isr_irq11(void);
|
||||
extern void _x86_isr_irq12(void);
|
||||
extern void _x86_isr_irq13(void);
|
||||
extern void _x86_isr_irq14(void);
|
||||
extern void _x86_isr_irq15(void);
|
||||
|
||||
/*
|
||||
* This file is part of GayBSD.
|
||||
* Copyright (c) 2021 fef <owo@fef.moe>.
|
||||
*
|
||||
* GayBSD is nonviolent software: you may only use, redistribute, and/or
|
||||
* modify it under the terms of the Cooperative Nonviolent Public License
|
||||
* (CNPL) as found in the LICENSE file in the source code root directory
|
||||
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
|
||||
* of the license, or (at your option) any later version.
|
||||
*
|
||||
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPL for details.
|
||||
*/
|
@ -0,0 +1,88 @@
|
||||
/* See the end of this file for copyright and license terms. */
|
||||
|
||||
#include <arch/port.h>
|
||||
|
||||
#include <asm/common.h>
|
||||
|
||||
#include <gay/config.h>
|
||||
|
||||
.data
|
||||
|
||||
/* void (*irq_table[NUM_IRQ])(void); */
|
||||
.extern irq_table
|
||||
|
||||
/* there is probably a fancy CPU feature for this, but idk */
|
||||
_in_irq:
|
||||
.byte 0
|
||||
|
||||
.text
|
||||
|
||||
/* bool in_irq(void); */
|
||||
ASM_ENTRY(in_irq)
|
||||
xor %eax, %eax
|
||||
movb _in_irq, %al
|
||||
ret
|
||||
ASM_END(in_irq)
|
||||
|
||||
.macro gen_irq num
|
||||
ASM_ENTRY(_x86_isr_irq\num )
|
||||
push %eax
|
||||
push %ecx
|
||||
push %edx
|
||||
movb $1, _in_irq
|
||||
#if CFG_DEBUG_IRQ
|
||||
pushl $\num
|
||||
#endif
|
||||
call *(irq_table + \num * 4)
|
||||
#if CFG_DEBUG_IRQ
|
||||
add $4, %esp
|
||||
#endif
|
||||
movb $0x20, %al /* PIC End Of Interrupt command code */
|
||||
.if \num >= 8
|
||||
jmp leave_irq_pic2
|
||||
.else
|
||||
jmp leave_irq_pic1
|
||||
.endif
|
||||
ASM_END(_x86_isr_irq\num )
|
||||
.endm
|
||||
|
||||
gen_irq 0
|
||||
gen_irq 1
|
||||
/* IRQ 2 is for cascading from PIC2 to PIC1 */
|
||||
gen_irq 3
|
||||
gen_irq 4
|
||||
gen_irq 5
|
||||
gen_irq 6
|
||||
gen_irq 7
|
||||
gen_irq 8
|
||||
gen_irq 9
|
||||
gen_irq 10
|
||||
gen_irq 11
|
||||
gen_irq 12
|
||||
gen_irq 13
|
||||
gen_irq 14
|
||||
gen_irq 15
|
||||
|
||||
leave_irq_pic2:
|
||||
outb %al, $X86_PORT_PIC2_CMD /* send End Of Interrupt to PIC2 */
|
||||
leave_irq_pic1:
|
||||
outb %al, $X86_PORT_PIC1_CMD /* send End Of Interrupt to PIC1 */
|
||||
movb $0, _in_irq
|
||||
pop %edx
|
||||
pop %ecx
|
||||
pop %eax
|
||||
iret
|
||||
|
||||
/*
|
||||
* This file is part of GayBSD.
|
||||
* Copyright (c) 2021 fef <owo@fef.moe>.
|
||||
*
|
||||
* GayBSD is nonviolent software: you may only use, redistribute, and/or
|
||||
* modify it under the terms of the Cooperative Nonviolent Public License
|
||||
* (CNPL) as found in the LICENSE file in the source code root directory
|
||||
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
|
||||
* of the license, or (at your option) any later version.
|
||||
*
|
||||
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPL for details.
|
||||
*/
|
@ -0,0 +1,111 @@
|
||||
/* See the end of this file for copyright and license terms. */
|
||||
|
||||
#include <arch/irq.h>
|
||||
#include <arch/port.h>
|
||||
#include <arch/trap.h>
|
||||
|
||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
||||
|
||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
||||
|
||||
void arch_irq_init(void)
|
||||
{
|
||||
x86_set_intr_gate(X86_VECT_IRQ(0), _x86_isr_irq0);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(1), _x86_isr_irq1);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(3), _x86_isr_irq3);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(4), _x86_isr_irq4);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(5), _x86_isr_irq5);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(6), _x86_isr_irq6);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(7), _x86_isr_irq7);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(8), _x86_isr_irq8);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(9), _x86_isr_irq9);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(10), _x86_isr_irq10);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(11), _x86_isr_irq11);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(12), _x86_isr_irq12);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(13), _x86_isr_irq13);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(14), _x86_isr_irq14);
|
||||
x86_set_intr_gate(X86_VECT_IRQ(15), _x86_isr_irq15);
|
||||
|
||||
/* begin initialization sequence in cascade mode */
|
||||
x86_outb(X86_PORT_PIC1_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
x86_io_wait();
|
||||
x86_outb(X86_PORT_PIC2_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
x86_io_wait();
|
||||
|
||||
/* tell PIC1 its offset into the vector table */
|
||||
x86_outb(X86_PORT_PIC1_DATA, X86_VECT_IRQ_BASE);
|
||||
x86_io_wait();
|
||||
/* tell PIC2 its offset into the vector table */
|
||||
x86_outb(X86_PORT_PIC2_DATA, X86_VECT_IRQ_BASE + 8);
|
||||
x86_io_wait();
|
||||
|
||||
/* tell PIC1 that PIC2 is cascading into it on IRQ 2 */
|
||||
x86_outb(X86_PORT_PIC1_DATA, 1 << 2);
|
||||
x86_io_wait();
|
||||
/* tell PIC2 that it is the second controller in the cascade chain */
|
||||
x86_outb(X86_PORT_PIC2_DATA, 2);
|
||||
x86_io_wait();
|
||||
|
||||
/* don't ask me what the fuck this does */
|
||||
x86_outb(X86_PORT_PIC1_DATA, ICW4_8086);
|
||||
x86_io_wait();
|
||||
x86_outb(X86_PORT_PIC2_DATA, ICW4_8086);
|
||||
x86_io_wait();
|
||||
|
||||
/* mask all IRQs */
|
||||
x86_outb(X86_PORT_PIC1_DATA, 0xff);
|
||||
x86_io_wait();
|
||||
x86_outb(X86_PORT_PIC2_DATA, 0xff);
|
||||
}
|
||||
|
||||
void arch_irq_enable(unsigned int number)
|
||||
{
|
||||
u16 port;
|
||||
if (number >= 8) {
|
||||
port = X86_PORT_PIC2_DATA;
|
||||
number -= 8;
|
||||
} else {
|
||||
port = X86_PORT_PIC1_DATA;
|
||||
}
|
||||
|
||||
u8 mask = x86_inb(port);
|
||||
mask &= ~(1 << number);
|
||||
x86_outb(port, mask);
|
||||
}
|
||||
|
||||
void arch_irq_disable(unsigned int number)
|
||||
{
|
||||
u16 port;
|
||||
if (number >= 8) {
|
||||
port = X86_PORT_PIC2_DATA;
|
||||
number -= 8;
|
||||
} else {
|
||||
port = X86_PORT_PIC1_DATA;
|
||||
}
|
||||
|
||||
u8 mask = x86_inb(port);
|
||||
mask |= (1 << number);
|
||||
x86_outb(port, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* This file is part of GayBSD.
|
||||
* Copyright (c) 2021 fef <owo@fef.moe>.
|
||||
*
|
||||
* GayBSD is nonviolent software: you may only use, redistribute, and/or
|
||||
* modify it under the terms of the Cooperative Nonviolent Public License
|
||||
* (CNPL) as found in the LICENSE file in the source code root directory
|
||||
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
|
||||
* of the license, or (at your option) any later version.
|
||||
*
|
||||
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPL for details.
|
||||
*/
|
@ -0,0 +1,62 @@
|
||||
/* See the end of this file for copyright and license terms. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <gay/types.h>
|
||||
|
||||
extern void (*irq_table[NUM_IRQ])(void);
|
||||
|
||||
/** @brief Return true if you are in IRQ context. */
|
||||
bool in_irq(void);
|
||||
|
||||
/** @brief Initialize the IRQ table and interrupt controller. */
|
||||
void irq_init(void);
|
||||
|
||||
/**
|
||||
* @brief Enable (unmask) an IRQ.
|
||||
*
|
||||
* @param number IRQ number
|
||||
* @returns 0 on success, or a negative number if there is no associated handler
|
||||
*/
|
||||
int irq_enable(unsigned int number);
|
||||
|
||||
/**
|
||||
* @brief Disable (mask) an IRQ.
|
||||
*
|
||||
* @param number IRQ number
|
||||
*/
|
||||
void irq_disable(unsigned int number);
|
||||
|
||||
/**
|
||||
* @brief Attach a handler to a specific IRQ.
|
||||
*
|
||||
* @param number IRQ number
|
||||
* @param handler IRQ handler
|
||||
* @return 0 on success, or `-EEXIST` if the IRQ is already attached
|
||||
* to another handler (use `irq_detach()` to, well, detach handlers
|
||||
* that are no longer in use)
|
||||
*/
|
||||
int irq_attach(unsigned int number, void (*handler)(void));
|
||||
|
||||
/**
|
||||
* @brief Detach an IRQ handler that was attached using `irq_attach()`.
|
||||
*
|
||||
* @param number IRQ number
|
||||
*/
|
||||
void irq_detach(unsigned int number);
|
||||
|
||||
/*
|
||||
* This file is part of GayBSD.
|
||||
* Copyright (c) 2021 fef <owo@fef.moe>.
|
||||
*
|
||||
* GayBSD is nonviolent software: you may only use, redistribute, and/or
|
||||
* modify it under the terms of the Cooperative Nonviolent Public License
|
||||
* (CNPL) as found in the LICENSE file in the source code root directory
|
||||
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
|
||||
* of the license, or (at your option) any later version.
|
||||
*
|
||||
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPL for details.
|
||||
*/
|
@ -0,0 +1,83 @@
|
||||
/* See the end of this file for copyright and license terms. */
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include <gay/config.h>
|
||||
#include <gay/errno.h>
|
||||
#include <gay/irq.h>
|
||||
#include <gay/kprintf.h>
|
||||
|
||||
void (*irq_table[NUM_IRQ])(void);
|
||||
|
||||
#if CFG_DEBUG_IRQ
|
||||
/*
|
||||
* If CFG_DEBUG_IRQ is set, the IRQ entry points pass the IRQ number
|
||||
* as an argument to the IRQ handler (see arch/<arch>/sys/irq.S).
|
||||
*/
|
||||
static void do_unknown_irq(unsigned int number)
|
||||
{
|
||||
kprintf("Unknown IRQ %d encountered!\n", number);
|
||||
}
|
||||
# define UNKNOWN_IRQ_HANDLER ((void (*)(void))do_unknown_irq)
|
||||
#else
|
||||
static void do_unknown_irq(void)
|
||||
{
|
||||
kprintf("Unknown IRQ encountered!\n");
|
||||
}
|
||||
# define UNKNOWN_IRQ_HANDLER (do_unknown_irq)
|
||||
#endif
|
||||
|
||||
void irq_init(void)
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_IRQ; i++)
|
||||
irq_table[i] = UNKNOWN_IRQ_HANDLER;
|
||||
arch_irq_init();
|
||||
}
|
||||
|
||||
int irq_enable(unsigned int number)
|
||||
{
|
||||
if (number >= NUM_IRQ)
|
||||
return -ERANGE;
|
||||
if (irq_table[number] == UNKNOWN_IRQ_HANDLER)
|
||||
return -ENOENT;
|
||||
|
||||
arch_irq_enable(number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void irq_disable(unsigned int number)
|
||||
{
|
||||
if (number < NUM_IRQ)
|
||||
arch_irq_disable(number);
|
||||
}
|
||||
|
||||
int irq_attach(unsigned int number, void (*handler)(void))
|
||||
{
|
||||
if (number >= NUM_IRQ)
|
||||
return -ERANGE;
|
||||
if (irq_table[number] != UNKNOWN_IRQ_HANDLER)
|
||||
return -EEXIST;
|
||||
|
||||
irq_table[number] = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void irq_detach(unsigned int number)
|
||||
{
|
||||
if (number < NUM_IRQ)
|
||||
irq_table[number] = UNKNOWN_IRQ_HANDLER;
|
||||
}
|
||||
|
||||
/*
|
||||
* This file is part of GayBSD.
|
||||
* Copyright (c) 2021 fef <owo@fef.moe>.
|
||||
*
|
||||
* GayBSD is nonviolent software: you may only use, redistribute, and/or
|
||||
* modify it under the terms of the Cooperative Nonviolent Public License
|
||||
* (CNPL) as found in the LICENSE file in the source code root directory
|
||||
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
|
||||
* of the license, or (at your option) any later version.
|
||||
*
|
||||
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
* permitted by applicable law. See the CNPL for details.
|
||||
*/
|
Loading…
Reference in New Issue